Skip to content
This repository has been archived by the owner on May 24, 2024. It is now read-only.

[terra-menu] - Fixed SR not announcing menu group name information. #1841

Merged
merged 8 commits into from
Oct 31, 2023
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
20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions packages/terra-collapsible-menu-view/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Added
* Added `GroupId` prop that used in menu item for `aria-describedby` that labels the group for accessibility.

## 6.83.0 - (October 25, 2023)

* Changed
Expand All @@ -23,7 +26,7 @@
* Added the ability to add hyperlinks.
* Added `isMultiSelect` prop to support multiselect group items.
* Added aria-label prop for `collapsible-menu-view` to announce group information.

* Fixed
* Fixed responsive menu icon not being vertical in the lowlight and fusion themes.

Expand Down Expand Up @@ -105,7 +108,7 @@
* Added
* Added `isStartAligned` prop
* Added new Jest test and snapshots

## 6.65.0 - (March 29, 2023)

* Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ const propTypes = {
* String that labels the group for accessibility.
*/
ariaLabel: PropTypes.string,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need this prop along with this prop we need to create a prop for GroupId so that it can be used in menu item for aria-describedby attribute.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated - 4cf4469

/**
* String that used in menu item for aria-describedby that labels the group for accessibility.
*/
groupId: PropTypes.string,
};

const defaultProps = {
Expand Down Expand Up @@ -75,6 +79,7 @@ class CollapsibleMenuViewItemGroup extends React.Component {
isMultiSelect,
selectedKeys,
ariaLabel,
groupId,
...customProps
} = this.props;

Expand All @@ -90,7 +95,7 @@ class CollapsibleMenuViewItemGroup extends React.Component {
});
return (
<li role="none">
<div {...customProps} role="group">
<div {...customProps} role="group" id={groupId} aria-label={ariaLabel}>
{cloneChildren}
</div>
</li>
Expand All @@ -99,7 +104,7 @@ class CollapsibleMenuViewItemGroup extends React.Component {
if (onChange) {
return (
<li role="none">
<Menu.ItemGroup {...customProps} onChange={this.handleMenuOnChange} aria-label={ariaLabel}>
<Menu.ItemGroup {...customProps} onChange={this.handleMenuOnChange} id={groupId} aria-label={ariaLabel}>
{children}
</Menu.ItemGroup>
</li>
Expand Down
3 changes: 3 additions & 0 deletions packages/terra-framework-docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Added
* Added `aria-label` and `ariaDescribedBy` props.

## 1.43.0 - (October 25, 2023)

* Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ class AlwaysCollapsedMenuItemsDemo extends React.Component {
]}
/>
<CollapsibleMenuView.Divider key="divider1" />
<CollapsibleMenuView.ItemGroup ariaLabel="View Type Single Selection" key="ViewTypeSelection" selectedKeys={[this.state.displayType]} onChange={this.handleDisplayTypeChange}>
<CollapsibleMenuView.ItemGroup ariaLabel="View Type Single Selection" groupId="view-type-single-select" key="ViewTypeSelection" selectedKeys={[this.state.displayType]} onChange={this.handleDisplayTypeChange}>
<CollapsibleMenuView.Item
icon={<IconTable />}
text="Table View"
key="tableView"
ariaDescribedBy="view-type-single-select"
isIconOnly
shouldCloseOnClick={false}
isSelected={this.state.displayType === 'tableView'}
Expand All @@ -66,6 +67,7 @@ class AlwaysCollapsedMenuItemsDemo extends React.Component {
icon={<IconVisualization />}
text="Chart View"
key="chartView"
ariaDescribedBy="view-type-single-select"
isIconOnly
shouldCloseOnClick={false}
isSelected={this.state.displayType === 'chartView'}
Expand All @@ -74,6 +76,7 @@ class AlwaysCollapsedMenuItemsDemo extends React.Component {
icon={<IconTreemap />}
text="Treemap View"
key="treemapView"
ariaDescribedBy="view-type-single-select"
isIconOnly
shouldCloseOnClick={false}
isSelected={this.state.displayType === 'treemapView'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,12 @@ class CollapsibleMenuViewDemo extends React.Component {
]}
/>
<CollapsibleMenuView.Divider key="Divider2" />
<CollapsibleMenuView.ItemGroup ariaLabel="View Type Single Selection" key="ViewTypeSelection" selectedKeys={[this.state.displayType]} onChange={this.handleDisplayTypeChange}>
<CollapsibleMenuView.ItemGroup ariaLabel="View Type Single Selection" groupId="view-type-single-select" key="ViewTypeSelection" selectedKeys={[this.state.displayType]} onChange={this.handleDisplayTypeChange}>
<CollapsibleMenuView.Item
icon={<IconTable />}
text="Table View"
key="tableView"
ariaDescribedBy="view-type-single-select"
isIconOnly
shouldCloseOnClick={false}
isSelected={this.state.displayType === 'tableView'}
Expand All @@ -103,6 +104,7 @@ class CollapsibleMenuViewDemo extends React.Component {
icon={<IconVisualization />}
text="Chart View"
key="chartView"
ariaDescribedBy="view-type-single-select"
isIconOnly
shouldCloseOnClick={false}
isSelected={this.state.displayType === 'chartView'}
Expand All @@ -111,6 +113,7 @@ class CollapsibleMenuViewDemo extends React.Component {
icon={<IconTreemap />}
text="Treemap View"
key="treemapView"
ariaDescribedBy="view-type-single-select"
isIconOnly
shouldCloseOnClick={false}
isSelected={this.state.displayType === 'treemapView'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,12 @@ class CollapsibleMenuViewStartAligned extends React.Component {
]}
/>
<CollapsibleMenuView.Divider key="Divider2" />
<CollapsibleMenuView.ItemGroup ariaLabel="View Type Single Selection" key="ViewTypeSelection" selectedKeys={[this.state.displayType]} onChange={this.handleDisplayTypeChange}>
<CollapsibleMenuView.ItemGroup ariaLabel="View Type Single Selection" groupId="view-type-single-select" key="ViewTypeSelection" selectedKeys={[this.state.displayType]} onChange={this.handleDisplayTypeChange}>
<CollapsibleMenuView.Item
icon={<IconTable />}
text="Table View"
key="tableView"
ariaDescribedBy="view-type-single-select"
isIconOnly
shouldCloseOnClick={false}
isSelected={this.state.displayType === 'tableView'}
Expand All @@ -103,6 +104,7 @@ class CollapsibleMenuViewStartAligned extends React.Component {
icon={<IconVisualization />}
text="Chart View"
key="chartView"
ariaDescribedBy="view-type-single-select"
isIconOnly
shouldCloseOnClick={false}
isSelected={this.state.displayType === 'chartView'}
Expand All @@ -111,6 +113,7 @@ class CollapsibleMenuViewStartAligned extends React.Component {
icon={<IconTreemap />}
text="Treemap View"
key="treemapView"
ariaDescribedBy="view-type-single-select"
isIconOnly
shouldCloseOnClick={false}
isSelected={this.state.displayType === 'treemapView'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ class CollapsibleMenuViewWithMultiSelectItems extends React.Component {
]}
/>
<CollapsibleMenuView.Divider key="Divider2" />
<CollapsibleMenuView.ItemGroup ariaLabel="View Type Multi Selection" key="ViewTypeSelection" isMultiSelect selectedKeys={this.state.selectedKeys} onChange={this.handleDisplayTypeChange}>
<CollapsibleMenuView.ItemGroup ariaLabel="View Type Multi Selection" groupId="view-type-multi-select" key="ViewTypeSelection" isMultiSelect selectedKeys={this.state.selectedKeys} onChange={this.handleDisplayTypeChange}>
<CollapsibleMenuView.Item
icon={<IconTable />}
text="Table View"
key="tableView"
ariaDescribedBy="view-type-multi-select"
isIconOnly
shouldCloseOnClick={false}
isSelected={this.state.selectedKeys.includes('tableView')}
Expand All @@ -90,6 +91,7 @@ class CollapsibleMenuViewWithMultiSelectItems extends React.Component {
icon={<IconFlowsheet />}
text="Expanded View"
key="expandedView"
ariaDescribedBy="view-type-multi-select"
isIconOnly
shouldCloseOnClick={false}
isSelected={this.state.selectedKeys.includes('expandedView')}
Expand All @@ -98,6 +100,7 @@ class CollapsibleMenuViewWithMultiSelectItems extends React.Component {
icon={<IconVisualization />}
text="Trending View"
key="trendingView"
ariaDescribedBy="view-type-multi-select"
isIconOnly
shouldCloseOnClick={false}
isSelected={this.state.selectedKeys.includes('trendingView')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,10 @@ class BasicMenu extends React.Component {
]}
/>
<Menu.Divider key="Divider3" />
<Menu.ItemGroup key="Group" onChange={this.handleOnChange}>
<Menu.Item text="Behavioral Health" key="GroupItem1" isSelected={this.state.groupSelectedIndex === 0} />
<Menu.Item text="Ambulatory Surgery Center" key="GroupItem2" isSelected={this.state.groupSelectedIndex === 1} />
<Menu.Item text="Critical Care" key="GroupItem3" isSelected={this.state.groupSelectedIndex === 2} isDisabled />
<Menu.ItemGroup key="Group" aria-label="Health Information" id="health-info" onChange={this.handleOnChange}>
<Menu.Item ariaDescribedBy="health-info" text="Behavioral Health" key="GroupItem1" isSelected={this.state.groupSelectedIndex === 0} />
<Menu.Item ariaDescribedBy="health-info" text="Ambulatory Surgery Center" key="GroupItem2" isSelected={this.state.groupSelectedIndex === 1} />
<Menu.Item ariaDescribedBy="health-info" text="Critical Care" key="GroupItem3" isSelected={this.state.groupSelectedIndex === 2} isDisabled />
</Menu.ItemGroup>
</Menu>
<Button onClick={this.handleButtonClick} text="Explore Clinical Solution" aria-haspopup icon={<IconCaretDown />} isReversed refCallback={this.setButtonNode} />
Expand Down
9 changes: 6 additions & 3 deletions packages/terra-menu/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Added
* Added `ariaDescribedBy` prop for `menu-item` to announce group information.

## 6.79.0 - (October 25, 2023)

* Changed
Expand Down Expand Up @@ -98,9 +101,9 @@

## 6.65.1 - (April 12, 2023)

* Fixed
* Fixed
* Fixed issue of navigation on menu header click.

* Added
* Allow screen readers to recognise as menu button
* Added context for menu item index, item with submenu and selected/unselected state
Expand All @@ -114,7 +117,7 @@

* Changed
* Allow existing classnames on icon to be retained

## 6.63.0 - (February 14, 2023)

* Changed
Expand Down
6 changes: 6 additions & 0 deletions packages/terra-menu/src/MenuItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ const propTypes = {
* The intl object to be injected for translations. Provided by the injectIntl function.
*/
intl: PropTypes.shape({ formatMessage: PropTypes.func }).isRequired,
/**
* If additional visible information text is used, provide a string containing the IDs for html elements that
* help describe the intent of the group of menu.
*/
ariaDescribedBy: PropTypes.string,
};

const defaultProps = {
Expand Down Expand Up @@ -246,6 +251,7 @@ class MenuItem extends React.Component {
isInstructionsForUse,
isSelectable,
isToggleable,
ariaDescribedBy,
subMenuItems,
isActive,
icon,
Expand Down
16 changes: 13 additions & 3 deletions packages/terra-menu/src/_MenuContent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class MenuContent extends React.Component {
this.onKeyDown = this.onKeyDown.bind(this);
this.onKeyDownBackButton = this.onKeyDownBackButton.bind(this);
this.validateFocus = this.validateFocus.bind(this);
this.ariaDescribedByHandle = this.ariaDescribedByHandle.bind(this);
this.needsFocus = props.isFocused;
this.handleContainerRef = this.handleContainerRef.bind(this);
this.menuHeaderId = `terra-menu-headertitle-${uuidv4()}`;
Expand Down Expand Up @@ -342,6 +343,14 @@ class MenuContent extends React.Component {
);
}

ariaDescribedByHandle(value, index) {
Copy link
Contributor

@supreethmr supreethmr Oct 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function can be simplified to

    ariaDescribedByHandle(value, index) {
      if (!MenuUtils.isMac() && !this.props.index && this.props.showHeader && index === 0) {
        let ariaDescribedByValue = (value.props.ariaDescribedBy) ? `, ${value.props.ariaDescribedBy}` : '';
        return `${this.menuTopHeaderId}${ariaDescribedByValue}`;
      }
      return value.props.ariaDescribedBy;
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated - 37d673e

if (!MenuUtils.isMac() && !this.props.index && this.props.showHeader && index === 0) {
const ariaDescribedByValue = (value.props.ariaDescribedBy) ? ` ${value.props.ariaDescribedBy}` : '';
return `${this.menuTopHeaderId}${ariaDescribedByValue}`;
}
return value.props.ariaDescribedBy;
}

render() {
let index = -1;
const totalItems = MenuUtils.totalItems(this.props.children);
Expand All @@ -356,28 +365,29 @@ class MenuContent extends React.Component {
index += 1;
const onKeyDown = this.wrapOnKeyDown(item, index, item.props.isDisabled);
const isActive = this.state.focusIndex === index;

const ariaDescribedByHandleValue = this.ariaDescribedByHandle(item, index);
newItem = React.cloneElement(item, {
onClick,
onKeyDown,
isActive,
totalItems,
index,
intl: this.props.intl,
'aria-describedby': !MenuUtils.isMac() && !this.props.index && this.props.showHeader && index === 0 ? this.menuTopHeaderId : undefined,
'aria-describedby': ariaDescribedByHandleValue,
});
// If the child has children then it is an item group, so iterate through it's children
} else if (item.props.children) {
const children = item.props.children ? [] : undefined;
React.Children.forEach(item.props.children, (child) => {
index += 1;
const ariaDescribedByHandleValue = this.ariaDescribedByHandle(child, index);
const clonedElement = React.cloneElement(child, {
onKeyDown: this.wrapOnKeyDown(child, index, child.props.isDisabled),
isActive: index === this.state.focusIndex,
totalItems,
index,
intl: this.props.intl,
'aria-describedby': !MenuUtils.isMac() && !this.props.index && this.props.showHeader && index === 0 ? this.menuTopHeaderId : undefined,
'aria-describedby': ariaDescribedByHandleValue,
});
children.push(clonedElement);
});
Expand Down
Loading