From ab1393871b254c576427373124ff41bb726f355d Mon Sep 17 00:00:00 2001 From: Sivaraman Krishnan Date: Tue, 15 May 2018 13:36:03 -0700 Subject: [PATCH 1/7] change log --- .../experiments/master_2018-05-15-20-33.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/changes/@uifabric/experiments/master_2018-05-15-20-33.json diff --git a/common/changes/@uifabric/experiments/master_2018-05-15-20-33.json b/common/changes/@uifabric/experiments/master_2018-05-15-20-33.json new file mode 100644 index 0000000000000..8d1c8a52dd69e --- /dev/null +++ b/common/changes/@uifabric/experiments/master_2018-05-15-20-33.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@uifabric/experiments", + "comment": "Experiments/Nav: accessibility changes", + "type": "minor" + } + ], + "packageName": "@uifabric/experiments", + "email": "sikrishn@microsoft.com" +} \ No newline at end of file From 74ba7bc31e2f37b0aef0cc357cbce363257b95e2 Mon Sep 17 00:00:00 2001 From: Sivaraman Krishnan Date: Fri, 18 May 2018 17:17:45 -0700 Subject: [PATCH 2/7] deleted old change log file --- .../experiments/master_2018-05-15-20-33.json | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 common/changes/@uifabric/experiments/master_2018-05-15-20-33.json diff --git a/common/changes/@uifabric/experiments/master_2018-05-15-20-33.json b/common/changes/@uifabric/experiments/master_2018-05-15-20-33.json deleted file mode 100644 index 8d1c8a52dd69e..0000000000000 --- a/common/changes/@uifabric/experiments/master_2018-05-15-20-33.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "packageName": "@uifabric/experiments", - "comment": "Experiments/Nav: accessibility changes", - "type": "minor" - } - ], - "packageName": "@uifabric/experiments", - "email": "sikrishn@microsoft.com" -} \ No newline at end of file From 1e502068b18bc3c4c6357be1b888ff04d6c1ebb0 Mon Sep 17 00:00:00 2001 From: Sivaraman Krishnan Date: Tue, 22 May 2018 17:35:55 -0700 Subject: [PATCH 3/7] Added aria attributes to experiment/nav component --- .../experiments/src/components/Nav/Nav.styles.ts | 13 ++----------- packages/experiments/src/components/Nav/Nav.tsx | 11 ++++++++++- packages/experiments/src/components/Nav/SlimNav.tsx | 3 ++- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/experiments/src/components/Nav/Nav.styles.ts b/packages/experiments/src/components/Nav/Nav.styles.ts index a4b1a91aa333a..84b7b5a84f6a6 100644 --- a/packages/experiments/src/components/Nav/Nav.styles.ts +++ b/packages/experiments/src/components/Nav/Nav.styles.ts @@ -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': { + visibility: 'visible' } } }, @@ -111,7 +103,6 @@ export const getStyles = ( }, navFloatingRoot: [ { - displayName: 'ms-Nav-FloatingNav', display: 'block', visibility: 'hidden', position: 'absolute', diff --git a/packages/experiments/src/components/Nav/Nav.tsx b/packages/experiments/src/components/Nav/Nav.tsx index 6375d29276c1c..67610b4db1274 100644 --- a/packages/experiments/src/components/Nav/Nav.tsx +++ b/packages/experiments/src/components/Nav/Nav.tsx @@ -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 @@ -116,6 +122,9 @@ class NavComponent extends NavBase { dataHint={ dataHint } dataValue={ link.key } ariaLabel={ linkText } + { + ...ariaProps + } role="menu" rootClassName={ classNames.navItemRoot } leftIconName={ leftIconName } diff --git a/packages/experiments/src/components/Nav/SlimNav.tsx b/packages/experiments/src/components/Nav/SlimNav.tsx index 7554262bc1d99..7dc8b72f77a3d 100644 --- a/packages/experiments/src/components/Nav/SlimNav.tsx +++ b/packages/experiments/src/components/Nav/SlimNav.tsx @@ -114,7 +114,7 @@ class SlimNavComponent extends NavBase { } = this.props; const classNames = getClassNames(getStyles!, { isSelected, nestingLevel }); const linkText = this.getLinkText(link, showMore); - + return ( Date: Wed, 23 May 2018 17:18:46 -0700 Subject: [PATCH 4/7] js event to make the floating nav visible on key press --- .../src/components/Nav/SlimNav.tsx | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/experiments/src/components/Nav/SlimNav.tsx b/packages/experiments/src/components/Nav/SlimNav.tsx index 7dc8b72f77a3d..d61caf6714fbd 100644 --- a/packages/experiments/src/components/Nav/SlimNav.tsx +++ b/packages/experiments/src/components/Nav/SlimNav.tsx @@ -95,6 +95,42 @@ class SlimNavComponent extends NavBase { ev.stopPropagation(); } + private _onFocus(ev: React.SyntheticEvent): void { + if (!ev.nativeEvent) { + return; + } + + var a = (ev.nativeEvent.target as any); + + var floatingNav = a.parentElement.getElementsByTagName('div')[1]; + + if (floatingNav) { + floatingNav.style.visibility = 'visible'; + } + + // a.onblur = () => { + // floatingNav.style.visibility = 'hidden'; + // }; + } + + private _onBlur(ev: React.SyntheticEvent): void { + if (!ev.nativeEvent) { + return; + } + + var a = (ev.nativeEvent.target as any); + + var floatingNav = a.parentElement.getElementsByTagName('div')[1]; + + if (floatingNav) { + floatingNav.style.visibility = 'hidden'; + } + + // a.onblur = () => { + // floatingNav.style.visibility = 'hidden'; + // }; + } + private _renderCompositeLink(link: INavLink, linkIndex: number, nestingLevel: number): React.ReactElement<{}> | null { if (!link) { return null; @@ -114,7 +150,7 @@ class SlimNavComponent extends NavBase { } = this.props; const classNames = getClassNames(getStyles!, { isSelected, nestingLevel }); const linkText = this.getLinkText(link, showMore); - + return ( Date: Thu, 24 May 2018 15:02:33 -0700 Subject: [PATCH 5/7] Keyboard support for the slim version of experiments/Nav component --- .../src/components/Nav/Nav.styles.ts | 5 +- .../src/components/Nav/SlimNav.tsx | 71 ++++++++++++------- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/packages/experiments/src/components/Nav/Nav.styles.ts b/packages/experiments/src/components/Nav/Nav.styles.ts index 84b7b5a84f6a6..5e7fdd417acd4 100644 --- a/packages/experiments/src/components/Nav/Nav.styles.ts +++ b/packages/experiments/src/components/Nav/Nav.styles.ts @@ -53,7 +53,7 @@ export const getStyles = ( fontSize: navFontSize, selectors: { 'li:hover >div': { - visibility: 'visible' + display: 'block' } } }, @@ -103,8 +103,7 @@ export const getStyles = ( }, navFloatingRoot: [ { - display: 'block', - visibility: 'hidden', + display: 'none', position: 'absolute', marginLeft: navCollapsedWidth, marginTop: -navItemHeight - (!!scrollTop && scrollTop > 0 ? scrollTop : 0), diff --git a/packages/experiments/src/components/Nav/SlimNav.tsx b/packages/experiments/src/components/Nav/SlimNav.tsx index d61caf6714fbd..e17f5d970370c 100644 --- a/packages/experiments/src/components/Nav/SlimNav.tsx +++ b/packages/experiments/src/components/Nav/SlimNav.tsx @@ -22,6 +22,10 @@ import { NavLink } from './NavLink'; const getClassNames = classNamesFunction(); class SlimNavComponent extends NavBase { + private _floatingNavIdPrefix = 'floatingNav'; + // store the previous floating nav shown to close when the current floating nav shows up. + private _prevFloatingNav: any; + constructor(props: INavProps) { super(props); @@ -95,40 +99,59 @@ class SlimNavComponent extends NavBase { ev.stopPropagation(); } - private _onFocus(ev: React.SyntheticEvent): void { - if (!ev.nativeEvent) { + private _getFloatingNav(parentElement: HTMLElement | null, floatingNavId: string): HTMLDivElement | undefined { + if (!parentElement || !floatingNavId) { return; } - var a = (ev.nativeEvent.target as any); - - var floatingNav = a.parentElement.getElementsByTagName('div')[1]; + const divs = (parentElement as HTMLElement).getElementsByTagName('div'); + const arrFloatingNav = (Array.prototype.slice.call(divs) as Array).filter((div: HTMLDivElement) => { + return !!div && div.id === floatingNavId; + }); - if (floatingNav) { - floatingNav.style.visibility = 'visible'; + if (arrFloatingNav.length > 0) { + return arrFloatingNav[0]; } - - // a.onblur = () => { - // floatingNav.style.visibility = 'hidden'; - // }; } - private _onBlur(ev: React.SyntheticEvent): void { - if (!ev.nativeEvent) { + private _onKeyDown(link: INavLink, ev: React.SyntheticEvent): void { + const nativeEvent = (ev as any); + if (nativeEvent.keyCode !== 13) { + // accept only enter key to open the floating nav from slim nav return; } - var a = (ev.nativeEvent.target as any); - - var floatingNav = a.parentElement.getElementsByTagName('div')[1]; + const a = nativeEvent.target as HTMLElement; + const li = a.parentElement; + const floatingNavId = this._floatingNavIdPrefix + link.key; + const currentFloatingNav = this._getFloatingNav(li, floatingNavId); - if (floatingNav) { - floatingNav.style.visibility = 'hidden'; + if (!currentFloatingNav) { + return; } - // a.onblur = () => { - // floatingNav.style.visibility = 'hidden'; - // }; + 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 { @@ -224,9 +247,10 @@ class SlimNavComponent extends NavBase { const hasChildren = (!!link.links && link.links.length > 0); const { getStyles } = this.props; const classNames = getClassNames(getStyles!, { hasChildren, scrollTop: link.scrollTop }); + const floatingNavId = this._floatingNavIdPrefix + link.key; return ( -
+
{ this._renderFloatingLinks([link], 0 /* nestingLevel */) } @@ -257,8 +281,7 @@ class SlimNavComponent extends NavBase { key={ link.key || linkIndex } onMouseEnter={ this._onLinkMouseEnterOrLeave.bind(this, link) } onMouseLeave={ this._onLinkMouseEnterOrLeave.bind(this, link) } - onFocus={ this._onFocus.bind(this) } - // onBlur={ this._onBlur.bind(this) } + onKeyDown={ this._onKeyDown.bind(this, link) } title={ linkText } className={ classNames.navSlimItemRoot }> Date: Thu, 24 May 2018 15:21:56 -0700 Subject: [PATCH 6/7] Using custom attribute for the floating nav instead of id's --- .../experiments/src/components/Nav/SlimNav.tsx | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/experiments/src/components/Nav/SlimNav.tsx b/packages/experiments/src/components/Nav/SlimNav.tsx index e17f5d970370c..fb9da8e97057c 100644 --- a/packages/experiments/src/components/Nav/SlimNav.tsx +++ b/packages/experiments/src/components/Nav/SlimNav.tsx @@ -22,7 +22,6 @@ import { NavLink } from './NavLink'; const getClassNames = classNamesFunction(); class SlimNavComponent extends NavBase { - private _floatingNavIdPrefix = 'floatingNav'; // store the previous floating nav shown to close when the current floating nav shows up. private _prevFloatingNav: any; @@ -99,14 +98,14 @@ class SlimNavComponent extends NavBase { ev.stopPropagation(); } - private _getFloatingNav(parentElement: HTMLElement | null, floatingNavId: string): HTMLDivElement | undefined { - if (!parentElement || !floatingNavId) { + private _getFloatingNav(parentElement: HTMLElement | null): HTMLDivElement | undefined { + if (!parentElement) { return; } - const divs = (parentElement as HTMLElement).getElementsByTagName('div'); + const divs = parentElement.getElementsByTagName('div'); const arrFloatingNav = (Array.prototype.slice.call(divs) as Array).filter((div: HTMLDivElement) => { - return !!div && div.id === floatingNavId; + return !!div && !!div.getAttribute('data-floating-nav'); }); if (arrFloatingNav.length > 0) { @@ -123,8 +122,7 @@ class SlimNavComponent extends NavBase { const a = nativeEvent.target as HTMLElement; const li = a.parentElement; - const floatingNavId = this._floatingNavIdPrefix + link.key; - const currentFloatingNav = this._getFloatingNav(li, floatingNavId); + const currentFloatingNav = this._getFloatingNav(li); if (!currentFloatingNav) { return; @@ -247,10 +245,9 @@ class SlimNavComponent extends NavBase { const hasChildren = (!!link.links && link.links.length > 0); const { getStyles } = this.props; const classNames = getClassNames(getStyles!, { hasChildren, scrollTop: link.scrollTop }); - const floatingNavId = this._floatingNavIdPrefix + link.key; return ( -
+
{ this._renderFloatingLinks([link], 0 /* nestingLevel */) } From 8c670ede6e2f4649d42064ee7b58cb11209a4662 Mon Sep 17 00:00:00 2001 From: Sivaraman Krishnan Date: Thu, 24 May 2018 15:47:13 -0700 Subject: [PATCH 7/7] Simplified query selector and added change log file --- .../experiments/master_2018-05-24-22-44.json | 11 +++++++++++ packages/experiments/src/components/Nav/SlimNav.tsx | 9 +-------- 2 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 common/changes/@uifabric/experiments/master_2018-05-24-22-44.json diff --git a/common/changes/@uifabric/experiments/master_2018-05-24-22-44.json b/common/changes/@uifabric/experiments/master_2018-05-24-22-44.json new file mode 100644 index 0000000000000..1105afbb9792b --- /dev/null +++ b/common/changes/@uifabric/experiments/master_2018-05-24-22-44.json @@ -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" +} \ No newline at end of file diff --git a/packages/experiments/src/components/Nav/SlimNav.tsx b/packages/experiments/src/components/Nav/SlimNav.tsx index fb9da8e97057c..cfbf1f91f8b94 100644 --- a/packages/experiments/src/components/Nav/SlimNav.tsx +++ b/packages/experiments/src/components/Nav/SlimNav.tsx @@ -103,14 +103,7 @@ class SlimNavComponent extends NavBase { return; } - const divs = parentElement.getElementsByTagName('div'); - const arrFloatingNav = (Array.prototype.slice.call(divs) as Array).filter((div: HTMLDivElement) => { - return !!div && !!div.getAttribute('data-floating-nav'); - }); - - if (arrFloatingNav.length > 0) { - return arrFloatingNav[0]; - } + return parentElement.querySelector('[data-floating-nav]') as HTMLDivElement; } private _onKeyDown(link: INavLink, ev: React.SyntheticEvent): void {