From 038c1636e3907c49009afda5d6192d660a6f8ea1 Mon Sep 17 00:00:00 2001 From: DanisAvko Date: Fri, 26 Jul 2024 13:14:20 +0300 Subject: [PATCH] feat(Table): aria-(colcount,colindex,rowcount,rowindex) support added --- src/components/FooterRow/FooterRow.tsx | 5 +++-- src/components/HeaderCell/HeaderCell.tsx | 2 ++ src/components/HeaderRow/HeaderRow.tsx | 6 ++++-- src/components/Row/Row.tsx | 20 +++++++++++++++++--- src/components/Table/Table.tsx | 13 ++++++++++++- src/utils/getHeaderCellCollIndex.ts | 7 +++++++ 6 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 src/utils/getHeaderCellCollIndex.ts diff --git a/src/components/FooterRow/FooterRow.tsx b/src/components/FooterRow/FooterRow.tsx index 59d8d07..607ee24 100644 --- a/src/components/FooterRow/FooterRow.tsx +++ b/src/components/FooterRow/FooterRow.tsx @@ -6,7 +6,7 @@ import type {FooterCellProps} from '../FooterCell'; import {FooterCell} from '../FooterCell'; import {b} from '../Table/Table.classname'; -export interface FooterRowProps { +export interface FooterRowProps extends React.TdHTMLAttributes { cellClassName: FooterCellProps['className']; className?: string; footerGroup: HeaderGroup; @@ -16,6 +16,7 @@ export const FooterRow = ({ cellClassName, className, footerGroup, + ...restProps }: FooterRowProps) => { const isEmptyRow = footerGroup.headers.every((header) => !header.column.columnDef.footer); @@ -24,7 +25,7 @@ export const FooterRow = ({ } return ( - + {footerGroup.headers.map((header) => ( ))} diff --git a/src/components/HeaderCell/HeaderCell.tsx b/src/components/HeaderCell/HeaderCell.tsx index 7b8df44..f545ffe 100644 --- a/src/components/HeaderCell/HeaderCell.tsx +++ b/src/components/HeaderCell/HeaderCell.tsx @@ -4,6 +4,7 @@ import type {Header} from '@tanstack/react-table'; import {flexRender} from '@tanstack/react-table'; import {getCellStyles, getHeaderCellClassModes} from '../../utils'; +import {getHeaderCellCollIndex} from '../../utils/getHeaderCellCollIndex'; import type {ResizeHandleProps} from '../ResizeHandle'; import {ResizeHandle} from '../ResizeHandle'; import type {SortIndicatorProps} from '../SortIndicator'; @@ -60,6 +61,7 @@ export const HeaderCell = ({ rowSpan={rowSpan > 1 ? rowSpan : undefined} onClick={header.column.getToggleSortingHandler()} style={getCellStyles(header)} + aria-colindex={getHeaderCellCollIndex(header)} > {flexRender(header.column.columnDef.header, header.getContext())}{' '} {header.column.getCanSort() && diff --git a/src/components/HeaderRow/HeaderRow.tsx b/src/components/HeaderRow/HeaderRow.tsx index 328c85f..0399766 100644 --- a/src/components/HeaderRow/HeaderRow.tsx +++ b/src/components/HeaderRow/HeaderRow.tsx @@ -7,7 +7,8 @@ import {HeaderCell} from '../HeaderCell'; import type {ResizeHandleProps} from '../ResizeHandle'; import {b} from '../Table/Table.classname'; -export interface HeaderRowProps { +export interface HeaderRowProps + extends Omit, 'className'> { cellClassName?: HeaderCellProps['className']; className?: | string @@ -29,6 +30,7 @@ export const HeaderRow = ({ renderSortIndicator, resizeHandleClassName, sortIndicatorClassName, + ...restProps }: HeaderRowProps) => { const className = React.useMemo(() => { return typeof classNameProp === 'function' @@ -37,7 +39,7 @@ export const HeaderRow = ({ }, [classNameProp, headerGroup, parentHeaderGroup]); return ( - + {headerGroup.headers.map((header) => ( { +export interface RowProps + extends Omit, 'className' | 'onClick'> { cellClassName?: CellProps['className']; className?: string | ((row: RowType) => string); getGroupTitle?: (row: RowType) => React.ReactNode; @@ -57,6 +58,7 @@ export const Row = React.forwardRef( rowVirtualizer, style, virtualItem, + ...restProps }: RowProps, ref: React.Ref, ) => { @@ -83,7 +85,11 @@ export const Row = React.forwardRef( row, }) ) : ( - + {renderGroupHeader ? ( renderGroupHeader({ className: b('group-header', groupHeaderClassName), @@ -107,7 +113,14 @@ export const Row = React.forwardRef( return row .getVisibleCells() - .map((cell) => ); + .map((cell) => ( + + )); }; return ( @@ -127,6 +140,7 @@ export const Row = React.forwardRef( )} onClick={handleClick} data-index={virtualItem?.index} + {...restProps} {...getRowAttributes?.(row)} > {renderRowContent()} diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index 7e1f81d..af5abde 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -98,12 +98,20 @@ export const Table = React.forwardRef( const headerGroups = withHeader && table.getHeaderGroups(); const footerGroups = withFooter && table.getFooterGroups(); + const colCount = table.getVisibleLeafColumns().length; + const headerRowCount = headerGroups ? headerGroups.length : 0; + const bodyRowCount = rows.length; + const footerRowCount = footerGroups ? footerGroups.length : 0; + const rowCount = bodyRowCount + headerRowCount + footerRowCount; + return ( -1 ? draggingRowIndex : undefined} + aria-colcount={colCount > 0 ? colCount : undefined} + aria-rowcount={rowCount > 0 ? rowCount : undefined} > {headerGroups && ( @@ -118,6 +126,7 @@ export const Table = React.forwardRef( renderSortIndicator={renderSortIndicator} resizeHandleClassName={resizeHandleClassName} sortIndicatorClassName={sortIndicatorClassName} + aria-rowindex={index + 1} /> ))} @@ -147,6 +156,7 @@ export const Table = React.forwardRef( virtualItem: rowVirtualizer ? (virtualItemOrRow as VirtualItem) : undefined, + 'aria-rowindex': headerRowCount + row.index + 1, }; if (draggableContext) { @@ -158,12 +168,13 @@ export const Table = React.forwardRef( {footerGroups && ( - {footerGroups.map((footerGroup) => ( + {footerGroups.map((footerGroup, index) => ( ))} diff --git a/src/utils/getHeaderCellCollIndex.ts b/src/utils/getHeaderCellCollIndex.ts new file mode 100644 index 0000000..a353a0d --- /dev/null +++ b/src/utils/getHeaderCellCollIndex.ts @@ -0,0 +1,7 @@ +import type {Header} from '@tanstack/react-table'; + +export const getHeaderCellCollIndex = (header: Header): number => { + return header.headerGroup.headers + .slice(0, header.index) + .reduce((acc, value) => acc + value.colSpan, 1); +};