Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@uifabric/experiments",
"comment": "Keyboard support for the slim version of experiments/Nav component and added aria attributes",
"type": "minor"
}
],
"packageName": "@uifabric/experiments",
"email": "sikrishn@microsoft.com"
}
16 changes: 3 additions & 13 deletions packages/experiments/src/components/Nav/Nav.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,8 @@ export const getStyles = (
margin: 0,
fontSize: navFontSize,
selectors: {
li: {
selectors: {
':hover': {
selectors: {
'>div[class*=ms-Nav-FloatingNav]': {
visibility: 'visible'
}
}
}
}
'li:hover >div': {
display: 'block'
}
}
},
Expand Down Expand Up @@ -111,9 +103,7 @@ export const getStyles = (
},
navFloatingRoot: [
{
displayName: 'ms-Nav-FloatingNav',
display: 'block',
visibility: 'hidden',
display: 'none',
position: 'absolute',
marginLeft: navCollapsedWidth,
marginTop: -navItemHeight - (!!scrollTop && scrollTop > 0 ? scrollTop : 0),
Expand Down
11 changes: 10 additions & 1 deletion packages/experiments/src/components/Nav/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,16 @@ class NavComponent extends NavBase {
return null;
}

let ariaProps = {};

let rightIconName = undefined;
if (link.links && link.links.length > 0 && nestingLevel === 0) {
// for the first level link, show chevron icon if there is a children
rightIconName = link.isExpanded ? 'ChevronUp' : 'ChevronDown'
rightIconName = link.isExpanded ? 'ChevronUp' : 'ChevronDown';

ariaProps = {
ariaExpanded: !!link.isExpanded
}
}
else if (link.url && link.target && link.target === '_blank') {
// for external links, show an icon
Expand Down Expand Up @@ -116,6 +122,9 @@ class NavComponent extends NavBase {
dataHint={ dataHint }
dataValue={ link.key }
ariaLabel={ linkText }
{
...ariaProps
}
role="menu"
rootClassName={ classNames.navItemRoot }
leftIconName={ leftIconName }
Expand Down
54 changes: 53 additions & 1 deletion packages/experiments/src/components/Nav/SlimNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import { NavLink } from './NavLink';
const getClassNames = classNamesFunction<INavStyleProps, INavStyles>();

class SlimNavComponent extends NavBase {
// store the previous floating nav shown to close when the current floating nav shows up.
private _prevFloatingNav: any;

constructor(props: INavProps) {
super(props);

Expand Down Expand Up @@ -95,6 +98,53 @@ class SlimNavComponent extends NavBase {
ev.stopPropagation();
}

private _getFloatingNav(parentElement: HTMLElement | null): HTMLDivElement | undefined {
if (!parentElement) {
return;
}

return parentElement.querySelector('[data-floating-nav]') as HTMLDivElement;
}

private _onKeyDown(link: INavLink, ev: React.SyntheticEvent<HTMLElement>): void {
const nativeEvent = (ev as any);
if (nativeEvent.keyCode !== 13) {
// accept only enter key to open the floating nav from slim nav
return;
}

const a = nativeEvent.target as HTMLElement;
const li = a.parentElement;
const currentFloatingNav = this._getFloatingNav(li);

if (!currentFloatingNav) {
return;
}

if (this._prevFloatingNav === currentFloatingNav) {
// toggle the floating nav
if (currentFloatingNav.style && currentFloatingNav.style.display && currentFloatingNav.style.display === 'block') {
currentFloatingNav.removeAttribute('style');
}
else {
currentFloatingNav.setAttribute('style', 'display: block');
}
}
else {
// prev and current floating navs are different
// close the previous if there is one
if (this._prevFloatingNav) {
this._prevFloatingNav.removeAttribute('style');
}

// open the current one
currentFloatingNav.setAttribute('style', 'display: block');

// store the current as prev
this._prevFloatingNav = currentFloatingNav;
}
}

private _renderCompositeLink(link: INavLink, linkIndex: number, nestingLevel: number): React.ReactElement<{}> | null {
if (!link) {
return null;
Expand Down Expand Up @@ -190,7 +240,7 @@ class SlimNavComponent extends NavBase {
const classNames = getClassNames(getStyles!, { hasChildren, scrollTop: link.scrollTop });

return (
<div className={ classNames.navFloatingRoot }>
<div className={ classNames.navFloatingRoot } data-floating-nav>
{
this._renderFloatingLinks([link], 0 /* nestingLevel */)
}
Expand Down Expand Up @@ -221,6 +271,7 @@ class SlimNavComponent extends NavBase {
key={ link.key || linkIndex }
onMouseEnter={ this._onLinkMouseEnterOrLeave.bind(this, link) }
onMouseLeave={ this._onLinkMouseEnterOrLeave.bind(this, link) }
onKeyDown={ this._onKeyDown.bind(this, link) }
title={ linkText }
className={ classNames.navSlimItemRoot }>
<NavLink
Expand All @@ -229,6 +280,7 @@ class SlimNavComponent extends NavBase {
target={ link.target }
dataHint={ dataHint }
dataValue={ link.key }
ariaLabel={ linkText }
role="menu"
onClick={ onClickHandler }
rootClassName={ classNames.navItemRoot }
Expand Down