Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { VirtualItem, Virtualizer } from '@tanstack/react-virtual';
import IconDesign from '@ui5/webcomponents/dist/types/IconDesign.js';
import IconMode from '@ui5/webcomponents/dist/types/IconMode.js';
import iconFilter from '@ui5/webcomponents-icons/dist/filter.js';
import iconGroup from '@ui5/webcomponents-icons/dist/group-2.js';
import iconSortAscending from '@ui5/webcomponents-icons/dist/sort-ascending.js';
Expand Down Expand Up @@ -236,18 +237,28 @@ export const ColumnHeader = (props: ColumnHeaderProps) => {
data-component-name={`AnalyticalTableHeaderIconsContainer-${columnId}`}
>
{isFiltered && (
<Icon design={IconDesign.NonInteractive} name={iconFilter} aria-hidden className={classNames.icon} />
<Icon
design={IconDesign.NonInteractive}
name={iconFilter}
className={classNames.icon}
mode={IconMode.Decorative}
/>
)}
{column.isSorted && (
<Icon
design={IconDesign.NonInteractive}
name={column.isSortedDesc ? iconSortDescending : iconSortAscending}
aria-hidden
className={classNames.icon}
mode={IconMode.Decorative}
/>
)}
{column.isGrouped && (
<Icon design={IconDesign.NonInteractive} name={iconGroup} aria-hidden className={classNames.icon} />
<Icon
design={IconDesign.NonInteractive}
name={iconGroup}
className={classNames.icon}
mode={IconMode.Decorative}
/>
)}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export const VirtualTableBody = (props: VirtualTableBodyProps) => {
key={`${visibleRowIndex}-${emptyRowCellProps.key}`}
data-empty-row-cell="true"
tabIndex={-1}
aria-hidden
aria-hidden="true"
style={{ ...emptyRowCellProps.style, cursor: 'unset', width: item.size }}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export const VirtualTableBodyContainer = (props: VirtualTableBodyContainerProps)
}}
data-component-name="AnalyticalTableBody"
tabIndex={-1}
role="rowgroup"
>
{isMounted && children}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export const VerticalResizer = (props: VerticalResizerProps) => {

return (
<div
aria-hidden="true"
className={classNames.verticalResizerContainer}
ref={verticalResizerRef}
onMouseDown={handleResizeStart}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import IconMode from '@ui5/webcomponents/dist/types/IconMode.js';
import ListItemType from '@ui5/webcomponents/dist/types/ListItemType.js';
import PopoverHorizontalAlign from '@ui5/webcomponents/dist/types/PopoverHorizontalAlign.js';
import PopoverPlacement from '@ui5/webcomponents/dist/types/PopoverPlacement.js';
Expand Down Expand Up @@ -218,7 +219,7 @@ export const ColumnHeaderModal = (instance: TableInstanceWithPopoverProps) => {
<Icon
name={iconFilter}
className={classNames.filterIcon}
aria-hidden
mode={IconMode.Decorative}
style={{
minWidth: filterStyles.iconDimensions,
minHeight: filterStyles.iconDimensions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import iconNavDownArrow from '@ui5/webcomponents-icons/dist/navigation-down-arro
import iconNavRightArrow from '@ui5/webcomponents-icons/dist/navigation-right-arrow.js';
import { CssSizeVariables, useCurrentTheme } from '@ui5/webcomponents-react-base';
import { clsx } from 'clsx';
import { Button, Icon } from '../../../../webComponents/index.js';
import type { FocusEvent } from 'react';
import type { ButtonDomRef } from '../../../../webComponents/Button/index.js';
import { Button } from '../../../../webComponents/Button/index.js';
import { Icon } from '../../../../webComponents/Icon/index.js';
import type { ColumnType, RowType, WCRPropertiesType } from '../../types/index.js';
import { RenderColumnTypes } from '../../types/index.js';

const getPadding = (level) => {
Expand All @@ -22,7 +26,15 @@ const getPadding = (level) => {
}
};

export const Expandable = (props) => {
interface ExpandableProps {
cell: Record<string, any>;
row: RowType;
column: ColumnType;
visibleColumns: ColumnType[];
webComponentsReactProperties: WCRPropertiesType;
}

export const Expandable = (props: ExpandableProps) => {
const { cell, row, column, visibleColumns: columns, webComponentsReactProperties } = props;
const {
renderRowSubComponent,
Expand Down Expand Up @@ -55,24 +67,37 @@ export const Expandable = (props) => {
title={row.isExpanded ? translatableTexts.collapseNodeA11yText : translatableTexts.expandNodeA11yText}
style={{ ...rowProps.style, paddingInlineStart: paddingLeft }}
className={classNames.container}
aria-label={row.isExpanded ? translatableTexts.collapseA11yText : translatableTexts.expandA11yText}
>
{shouldRenderButton ? (
<Button
tabIndex={-1}
icon={row.isExpanded ? iconNavDownArrow : iconNavRightArrow}
design={ButtonDesign.Transparent}
onClick={rowProps.onClick}
className={classNames.button}
onClick={rowProps.onClick}
accessibilityAttributes={{ expanded: row.isExpanded, hasPopup: false, controls: undefined }}
onFocus={(e: FocusEvent<ButtonDomRef>) => {
e.target.accessibleName = row.isExpanded
? translatableTexts.collapseNodeA11yText
: translatableTexts.expandNodeA11yText;
}}
onBlur={(e: FocusEvent<ButtonDomRef>) => {
e.target.accessibleName = '';
}}
/>
) : (
<Icon
aria-hidden="true"
tabIndex={-1}
onClick={rowProps.onClick}
mode={IconMode.Interactive}
name={row.isExpanded ? iconNavDownArrow : iconNavRightArrow}
aria-expanded={`${row.isExpanded}`}
data-component-name="AnalyticalTableExpandIcon"
className={classNames.expandableIcon}
accessibleName={
row.isExpanded ? translatableTexts.collapseNodeA11yText : translatableTexts.expandNodeA11yText
}
/>
)}
</span>
Expand All @@ -84,6 +109,14 @@ export const Expandable = (props) => {
classNames.nonExpandableCellSpacer,
shouldRenderButton && classNames.withExpandableButton
)}
onFocus={(e: FocusEvent<ButtonDomRef>) => {
e.target.accessibleName = row.isExpanded
? translatableTexts.collapseNodeA11yText
: translatableTexts.expandNodeA11yText;
}}
onBlur={(e: FocusEvent<ButtonDomRef>) => {
e.target.accessibleName = '';
}}
/>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { MouseEvent } from 'react';
import type { ReactTableHooks } from '../types/index.js';

const useGetResizerProps = (props) => {
return {
...props,
onMouseDown: (e) => {
'aria-hidden': 'true',
onMouseDown: (e: MouseEvent<HTMLDivElement>) => {
e.preventDefault();
props.onMouseDown(e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import { enrichEventWithDetails } from '@ui5/webcomponents-react-base';
import announce from '@ui5/webcomponents-base/dist/util/InvisibleMessage.js';
import { debounce, enrichEventWithDetails } from '@ui5/webcomponents-react-base';
import type { ReactTableHooks, RowType, TableInstance } from '../types/index.js';

// debounce announce to prevent excessive successive announcements
const debouncedAnnounce = debounce((announcement: string) => {
announce(announcement, 'Polite');
}, 200);

const getToggleRowExpandedProps = (
rowProps,
{ row, instance, userProps }: { row: RowType; instance: TableInstance; userProps: Record<string, any> }
) => {
const { manualGroupBy } = instance;
const { onRowExpandChange, isTreeTable, renderRowSubComponent, alwaysShowSubComponent } =
const { onRowExpandChange, isTreeTable, renderRowSubComponent, alwaysShowSubComponent, translatableTexts } =
instance.webComponentsReactProperties;

const onClick = (e, noPropagation = true) => {
if (noPropagation) {
e.stopPropagation();
Expand All @@ -30,6 +37,11 @@ const getToggleRowExpandedProps = (
);
}
row.toggleRowExpanded();
// cannot use ROW_X_COLLAPSED/ROW_X_EXPANDED here,
// as retrieving the index of the row is not easily possible here and has performance implications
debouncedAnnounce(
!row.isExpanded ? translatableTexts.rowExpandedAnnouncementText : translatableTexts.rowCollapsedAnnouncementText
);
};
const onKeyDown = (e) => {
if (e.code === 'F4') {
Expand Down
15 changes: 10 additions & 5 deletions packages/main/src/components/AnalyticalTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,12 @@ const AnalyticalTable = forwardRef<AnalyticalTableDomRef, AnalyticalTablePropTyp
filteredA11yText: i18nBundle.getText(FILTERED),
groupedA11yText: i18nBundle.getText(GROUPED),
selectAllA11yText: i18nBundle.getText(SELECT_ALL_PRESS_SPACE),
deselectAllA11yText: i18nBundle.getText(UNSELECT_ALL_PRESS_SPACE)
deselectAllA11yText: i18nBundle.getText(UNSELECT_ALL_PRESS_SPACE),
//todo: use translations once they are available
// rowExpandedAnnouncementText: i18nBundle.getText(ROW_EXPANDED),
// rowCollapsedAnnouncementText: i18nBundle.getText(ROW_COLLAPSED)
rowExpandedAnnouncementText: 'Row expanded',
rowCollapsedAnnouncementText: 'Row collapsed'
},
alternateRowColor,
alwaysShowSubComponent,
Expand Down Expand Up @@ -734,7 +739,7 @@ const AnalyticalTable = forwardRef<AnalyticalTableDomRef, AnalyticalTablePropTyp
{/*todo: use global CSS once --sapBlockLayer_Opacity is available*/}
{showOverlay && (
<>
<span id={invalidTableTextId} className={classNames.hiddenA11yText} aria-hidden>
<span id={invalidTableTextId} className={classNames.hiddenA11yText} aria-hidden="true">
{invalidTableA11yText}
</span>
<div
Expand All @@ -750,7 +755,7 @@ const AnalyticalTable = forwardRef<AnalyticalTableDomRef, AnalyticalTablePropTyp
aria-labelledby={titleBarId}
{...getTableProps()}
tabIndex={loading || showOverlay ? -1 : 0}
role="grid"
role={isTreeTable ? 'treegrid' : 'grid'}
aria-rowcount={rows.length}
aria-colcount={visibleColumns.length}
data-per-page={internalVisibleRowCount}
Expand All @@ -759,8 +764,8 @@ const AnalyticalTable = forwardRef<AnalyticalTableDomRef, AnalyticalTablePropTyp
ref={tableRef}
className={tableClasses}
>
<div className={classNames.tableHeaderBackgroundElement} />
<div className={classNames.tableBodyBackgroundElement} />
<div className={classNames.tableHeaderBackgroundElement} aria-hidden="true" />
<div className={classNames.tableBodyBackgroundElement} aria-hidden="true" />
{headerGroups.map((headerGroup) => {
let headerProps: Record<string, unknown> = {};
if (headerGroup.getHeaderGroupProps) {
Expand Down
2 changes: 2 additions & 0 deletions packages/main/src/components/AnalyticalTable/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ export interface WCRPropertiesType {
groupedA11yText: string;
selectAllA11yText: string;
deselectAllA11yText: string;
rowExpandedAnnouncementText: string;
rowCollapsedAnnouncementText: string;
};
tagNamesWhichShouldNotSelectARow: Set<string>;
tableRef: MutableRefObject<DivWithCustomScrollProp>;
Expand Down
12 changes: 12 additions & 0 deletions packages/main/src/i18n/messagebundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,18 @@ EXPAND_PRESS_SPACE=To expand the row, press the spacebar.
#XACT: Aria label text for expandable table cells in expanded state
COLLAPSE_PRESS_SPACE=To collapse the row, press the spacebar.

#XACT: general ARIA live announcement for expanded row
ROW_EXPANDED=Row expanded

#XACT: general ARIA live announcement for collapsed row
ROW_COLLAPSED=Row collapsed

#XACT: ARIA live announcement for expanded row number {0}
ROW_X_EXPANDED=Row {0} expanded

#XACT: ARIA live announcement for collapsed row number {0}
ROW_X_COLLAPSED=Row {0} collapsed

#XACT: Aria label text for selectable table cells in unselected state
SELECT_PRESS_SPACE=To select the row, press the spacebar.

Expand Down
Loading