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

[terra-navigation-side-menu] A11y changes #2166

Merged
merged 13 commits into from
May 21, 2024
Merged
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
3 changes: 3 additions & 0 deletions packages/terra-framework-docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -2,6 +2,9 @@

## Unreleased

* Changed
* Updated example for drill-in view under `terra-navigation-side-menu`.

## 1.89.1 - (May 20, 2024)

* Fixed
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ class DrillInDefault extends React.Component {
},
{ key: 'subsubmenu2', text: 'Laboratory' },
{
key: 'subsubmenu3', text: 'Rehabilitation services', childKeys: ['rehab1', 'rehab2', 'rehab3'], icon: <IconHospital />,
key: 'subsubmenu3', text: 'Rehabilitation services', childKeys: ['rehab1', 'rehab2', 'rehab3'], icon: <IconHospital a11yLabel="Location" />,
},
{ key: 'rehab1', text: 'Rehabilitation services 1' },
{ key: 'rehab2', text: 'Rehabilitation services 2' },
@@ -56,6 +56,7 @@ class DrillInDefault extends React.Component {
selectedChildKey={this.state.selectedChildKey}
ariaLabel="Sub Menu List"
variant={VARIANTS.DRILL_IN}
headerLevel={3}
/>
);

4 changes: 4 additions & 0 deletions packages/terra-navigation-side-menu/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -2,6 +2,10 @@

## Unreleased

* Added
* Added headerLevel prop for the title of the menu.
* Added missing A11y attributes.

## 2.58.1 - (May 20, 2024)

* Fixed
27 changes: 26 additions & 1 deletion packages/terra-navigation-side-menu/src/NavigationSideMenu.jsx
Original file line number Diff line number Diff line change
@@ -24,6 +24,10 @@ const propTypes = {
* String that labels the navigation menu for screen readers.
*/
ariaLabel: PropTypes.string,
/**
* The heading level for the title of the menu.
*/
headerLevel: PropTypes.oneOf([1, 2, 3, 4, 5, 6]),
/**
* An array of configuration for each menu item.
*/
@@ -96,6 +100,7 @@ const propTypes = {
const defaultProps = {
menuItems: [],
variant: VARIANTS.NAVIGATION_SIDE_MENU,
headerLevel: 3,
};

const processMenuItems = (menuItems, variant) => {
@@ -257,6 +262,16 @@ class NavigationSideMenu extends Component {
const listMenuItems = this.menuContainer && this.menuContainer.querySelectorAll('[data-menu-item]');
const currentIndex = Array.from(listMenuItems).indexOf(event.target);
const lastIndex = listMenuItems.length - 1;

if (event.nativeEvent.keyCode === KeyCode.KEY_ESCAPE) {
const parentKey = this.state.parents[this.props.selectedMenuKey];
if (parentKey) {
this.handleBackClick(event);
} else if (this.props.routingStackBack) {
this.props.routingStackBack();
}
}

if (event.nativeEvent.keyCode === KeyCode.KEY_SPACE || event.nativeEvent.keyCode === KeyCode.KEY_RETURN) {
event.preventDefault();
if (!item.isDisabled) {
@@ -379,6 +394,7 @@ class NavigationSideMenu extends Component {
selectedMenuKey,
toolbar,
variant,
headerLevel,
...customProps
} = this.props;
const currentItem = this.state.items[selectedMenuKey];
@@ -388,6 +404,8 @@ class NavigationSideMenu extends Component {
theme.className,
]);

const HeaderElement = `h${headerLevel}`;

const parentKey = this.state.parents[selectedMenuKey];
if (parentKey) {
this.onBack = this.handleBackClick;
@@ -400,6 +418,12 @@ class NavigationSideMenu extends Component {
theme.className,
]);

const titleStyles = cx([
'title',
{ 'nav-side-menu-title': (variant === VARIANTS.NAVIGATION_SIDE_MENU) },
{ 'drill-in-title': (variant === VARIANTS.DRILL_IN) },
]);

let header;
if (this.onBack || (currentItem && !currentItem.isRootMenu)) {
header = (
@@ -413,9 +437,10 @@ class NavigationSideMenu extends Component {
onKeyDown={this.handleBackKeydown}
onClick={this.onBack}
data-navigation-side-menu
aria-label={currentItem ? currentItem.text : null}
>
{(this.onBack) ? <span className={cx(['header-icon', 'back'])} /> : null}
<h1 className={cx('title')}>{currentItem ? currentItem.text : null}</h1>
<HeaderElement className={titleStyles}>{currentItem ? currentItem.text : null}</HeaderElement>
</div>
{toolbar}
</li>
Original file line number Diff line number Diff line change
@@ -75,13 +75,20 @@

.title {
color: var(--terra-navigation-side-menu-header-color);
font-size: var(--terra-navigation-side-menu-font-size, 1.10714rem);
font-weight: var(--terra-navigation-side-menu-font-weight, 500);
hyphens: auto;
margin: 5px;
overflow-wrap: break-word; /* Modern browsers */
padding: 0.28571rem;
width: 100%;
word-wrap: break-word; /* For IE 10 and IE 11 */
}

.nav-side-menu-title {
font-size: var(--terra-navigation-side-menu-font-size, 1.10714rem);
font-weight: var(--terra-navigation-side-menu-font-weight, 500);
}

.drill-in-title {
MadanKumarGovindaswamy marked this conversation as resolved.
Show resolved Hide resolved
font-weight: 700;
}
}
12 changes: 10 additions & 2 deletions packages/terra-navigation-side-menu/src/_MenuItem.jsx
Original file line number Diff line number Diff line change
@@ -120,7 +120,7 @@ class MenuItem extends React.Component {
} = this.props;
const theme = this.context;

const itemIcon = hasChevron && !icon ? <IconFolder /> : (icon || <IconDocuments />);
const itemIcon = hasChevron && !icon ? <IconFolder a11yLabel={intl.formatMessage({ id: 'Terra.navigation.side.menu.folder' })} /> : (icon || <IconDocuments a11yLabel={intl.formatMessage({ id: 'Terra.navigation.side.menu.document' })} />);

const itemClassNames = classNames(cx(
'menu-item',
@@ -137,6 +137,14 @@ class MenuItem extends React.Component {
{ 'is-disabled': isDisabled },
);

const ariaAttributes = {};
ariaAttributes['aria-haspopup'] = hasChevron;
ariaAttributes['aria-disabled'] = isDisabled;

if (hasChevron) {
ariaAttributes['aria-expanded'] = !hasChevron;
}

MadanKumarGovindaswamy marked this conversation as resolved.
Show resolved Hide resolved
return (
<li
className={listItemClassNames}
@@ -149,7 +157,7 @@ class MenuItem extends React.Component {
tabIndex={this.props.tabIndex}
className={itemClassNames}
onKeyDown={this.handleKeyDown}
aria-haspopup={hasChevron}
{...ariaAttributes}
>
{variant === VARIANTS.DRILL_IN && itemIcon && <span className={cx('icon')}>{itemIcon}</span>}
<div className={cx('title')}>
Loading