@@ -5,18 +5,34 @@ import type { ReactTableHooks, TableInstance } from '../types/index.js';
55
66interface UpdatedCellProptypes {
77 onKeyDown ?: KeyboardEventHandler < HTMLDivElement > ;
8- 'aria-expanded' ?: string | boolean ;
8+ 'aria-expanded' ?: string ;
99 'aria-label' ?: string ;
10- 'aria-colindex' ?: number ;
11- role ?: string ;
10+ 'aria-colindex' : number ;
11+ 'aria-describedby' ?: string ;
12+ 'aria-labelledby' : string ;
13+ role : string ;
1214}
1315
1416const setCellProps = ( cellProps , { cell, instance } : { cell : TableInstance [ 'cell' ] ; instance : TableInstance } ) => {
1517 const { column, row, value } = cell ;
1618 const columnIndex = instance . visibleColumns . findIndex ( ( { id } ) => id === column . id ) ;
17- const { alwaysShowSubComponent, renderRowSubComponent, translatableTexts, selectionMode, selectionBehavior } =
18- instance . webComponentsReactProperties ;
19- const updatedCellProps : UpdatedCellProptypes = { 'aria-colindex' : columnIndex + 1 , role : 'gridcell' } ; // aria index is 1 based, not 0
19+ const {
20+ alwaysShowSubComponent,
21+ renderRowSubComponent,
22+ selectionMode,
23+ selectionBehavior,
24+ a11yElementIds,
25+ uniqueId,
26+ canUseVoiceOver,
27+ } = instance . webComponentsReactProperties ;
28+
29+ const updatedCellProps : UpdatedCellProptypes = {
30+ // aria index is 1 based, not 0
31+ 'aria-colindex' : columnIndex + 1 ,
32+ role : 'gridcell' ,
33+ // header label
34+ 'aria-labelledby' : `${ uniqueId } ${ column . id } ${ row . id } ` + ( canUseVoiceOver ? ` ${ uniqueId } ${ column . id } ` : '' ) ,
35+ } ;
2036
2137 const RowSubComponent = typeof renderRowSubComponent === 'function' ? renderRowSubComponent ( row ) : undefined ;
2238 const rowIsExpandable = row . canExpand || ( RowSubComponent && ! alwaysShowSubComponent ) ;
@@ -30,24 +46,16 @@ const setCellProps = (cellProps, { cell, instance }: { cell: TableInstance['cell
3046
3147 const isFirstUserCol = userCols [ 0 ] ?. id === column . id || userCols [ 0 ] ?. accessor === column . accessor ;
3248 updatedCellProps [ 'data-is-first-column' ] = isFirstUserCol ;
33- updatedCellProps [ 'aria-label' ] = column . headerLabel || ( typeof column . Header === 'string' ? column . Header : '' ) ;
34- updatedCellProps [ 'aria-label' ] &&= `${ updatedCellProps [ 'aria-label' ] } ` ;
35- updatedCellProps [ 'aria-label' ] += value || value === 0 ? `${ value } ` : '' ;
3649
3750 if ( ( isFirstUserCol && rowIsExpandable ) || ( row . isGrouped && row . canExpand ) ) {
3851 updatedCellProps . onKeyDown = row . getToggleRowExpandedProps ?.( ) ?. onKeyDown ;
39- let ariaLabel = '' ;
40- if ( row . isGrouped ) {
41- ariaLabel += translatableTexts . groupedA11yText + ',' ;
42- }
4352 if ( row . isExpanded ) {
4453 updatedCellProps [ 'aria-expanded' ] = 'true' ;
45- ariaLabel += ` ${ translatableTexts . collapseA11yText } ` ;
54+ updatedCellProps [ 'aria-describedby' ] = ' ' + a11yElementIds . cellCollapseDescId ;
4655 } else {
4756 updatedCellProps [ 'aria-expanded' ] = 'false' ;
48- ariaLabel += ` ${ translatableTexts . expandA11yText } ` ;
57+ updatedCellProps [ 'aria-describedby' ] = ' ' + a11yElementIds . cellExpandDescId ;
4958 }
50- updatedCellProps [ 'aria-label' ] += ariaLabel ;
5159 } else if (
5260 ( selectionMode !== AnalyticalTableSelectionMode . None &&
5361 selectionBehavior !== AnalyticalTableSelectionBehavior . RowSelector &&
@@ -56,17 +64,21 @@ const setCellProps = (cellProps, { cell, instance }: { cell: TableInstance['cell
5664 ) {
5765 if ( row . isSelected ) {
5866 updatedCellProps [ 'aria-selected' ] = 'true' ;
59- updatedCellProps [ 'aria-label ' ] += ` ${ translatableTexts . unselectA11yText } ` ;
67+ updatedCellProps [ 'aria-describedby ' ] = ' ' + a11yElementIds . cellUnselectDescId ;
6068 } else {
6169 updatedCellProps [ 'aria-selected' ] = 'false' ;
62- updatedCellProps [ 'aria-label ' ] += ` ${ translatableTexts . selectA11yText } ` ;
70+ updatedCellProps [ 'aria-describedby ' ] = ' ' + a11yElementIds . cellSelectDescId ;
6371 }
6472 }
6573 const { cellLabel } = cell . column ;
6674 if ( typeof cellLabel === 'function' ) {
67- cell . cellLabel = updatedCellProps [ 'aria-label' ] ;
75+ const cellHeaderLabel = column . headerLabel || ( typeof column . Header === 'string' ? column . Header : '' ) ;
76+ const cellValueLabel = value || value === 0 ? `${ value } ` : '' ;
77+ cell . cellLabel = `${ cellHeaderLabel } ${ cellValueLabel } ` ;
6878 updatedCellProps [ 'aria-label' ] = cellLabel ( { cell, instance } ) ;
79+ updatedCellProps [ 'aria-labelledby' ] = undefined ;
6980 }
81+
7082 return [ cellProps , updatedCellProps ] ;
7183} ;
7284
@@ -108,11 +120,30 @@ const setHeaderProps = (
108120 : translatableTexts . selectAllA11yText ;
109121 }
110122
123+ if ( column . id === '__ui5wcr__internal_selection_column' ) {
124+ updatedProps [ 'aria-label' ] += ' ' + translatableTexts . selectionHeaderCellText ;
125+ }
126+
127+ if ( column . id === '__ui5wcr__internal_highlight_column' ) {
128+ updatedProps [ 'aria-label' ] += ' ' + translatableTexts . highlightHeaderCellText ;
129+ }
130+
131+ if ( column . id === '__ui5wcr__internal_navigation_column' ) {
132+ updatedProps [ 'aria-label' ] += ' ' + translatableTexts . navigationHeaderCellText ;
133+ }
134+
135+ updatedProps [ 'aria-label' ] ||= undefined ;
136+
111137 return [ headerProps , { isFiltered, ...updatedProps } ] ;
112138} ;
113139
140+ const setHeaderGroupProps = ( props ) => {
141+ return [ props , { 'aria-rowindex' : 1 } ] ;
142+ } ;
143+
114144export const useA11y = ( hooks : ReactTableHooks ) => {
115145 hooks . getCellProps . push ( setCellProps ) ;
116146 hooks . getHeaderProps . push ( setHeaderProps ) ;
147+ hooks . getHeaderGroupProps . push ( setHeaderGroupProps ) ;
117148} ;
118149useA11y . pluginName = 'useA11y' ;
0 commit comments