Skip to content

Commit

Permalink
BREAKING CHANGE: main nav mega menu update
Browse files Browse the repository at this point in the history
- created new utility function `getFocusableElementBySelector` this helps restrict our range to the areas of the menu we are in, not all the menu items
- separated out reusable parts of the `getFocusableElement` function
- updated `mega-navigation.json` to be multi level
- updated JS for main nav, not its robust enough to handle unlimited number of sub menus
- updated handlebars and created new files to reflect changes based off new mark up for multilevel nav
- updated css for main nav styling
  • Loading branch information
Sean Elliott committed Mar 18, 2020
1 parent 6babbb8 commit d1845b3
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 157 deletions.
68 changes: 37 additions & 31 deletions src/components/main-navigation/_main-navigation.scss
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
body {
background-color: $error-red;
.navigation-open {
overflow: hidden;
height: 100vh;
}

.nsw-navigation {
@include font-stack;
width: 100%;
position: absolute;
left: 0;
Expand All @@ -30,7 +27,6 @@ body {
}

@include breakpoint('md') {
@include font-stack('heading');
position: relative;
transform: none;
background-color: $light10;
Expand All @@ -39,6 +35,8 @@ body {
transition: none;
visibility: visible;
border-top: solid 1px $light40;
overflow-y: initial;
height: auto;
}

&__close {
Expand Down Expand Up @@ -125,7 +123,6 @@ body {
@include breakpoint('md') {
@include nsw-spacing(margin-top, xl);
display: flex;
justify-content: space-between;
}
}

Expand All @@ -143,12 +140,27 @@ body {
}
}

.nsw-navigation__list-item,
.nsw-subnavigation__list-item {
@include font-stack;

@include breakpoint('md') {
@include font-stack('heading');
border-bottom: 0;
}
}

.nsw-subnavigation__list-item {

@include breakpoint('md') {
width: 32%;
border-top: solid 1px $light20;

&:nth-child(3n+2) {
margin-left: 2%;
margin-right: 2%;
}

&:nth-last-child(-n+3) {
border-bottom: solid 1px $light20;
}
Expand Down Expand Up @@ -310,40 +322,34 @@ body {
@include nsw-spacing(margin, none);

@include breakpoint('md') {
@include font-size('lg');
display: inline-block;
}
}

// .nsw-subnavigation__title-link {
// color: $nsw-primary-blue;
// text-decoration: none;
// display: inline-flex;
// display: flex;
// flex-direction: row;
// align-items: stretch;
// flex-wrap: nowrap;

// &:hover {
// @include nsw-hover;
// }

// &:focus {
// @include nsw-focus;
// }

// .nsw-icon {
// @include nsw-spacing(margin-left, sm);
// margin-top: rem(4px);
// width: rem(24px);
// height: rem(24px);
// }
// }
.nsw-subnavigation__title-link {
@include breakpoint('md') {
@include nsw-spacing(padding, none);
color: $nsw-primary-blue;
}
}

.nsw-subnavigation__description {
@include nsw-spacing(margin-top, sm);
@include font-stack;
@include nsw-spacing(margin-top, md);
@include font-size('xs');
display: none;

@include breakpoint('md') {
display: block;
}
}

.nsw-subnavigation .nsw-subnavigation,
.nsw-subnavigation .nsw-navigation__link-icon {

@include breakpoint('md') {
display: none;
}

}
4 changes: 2 additions & 2 deletions src/components/main-navigation/_sub-nav.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="nsw-subnavigation" id="{{id}}-subnav" role="region" aria-label="{{text}} Submenu">
<div class="nsw-subnavigation" id="subnav-{{id}}" role="region" aria-label="{{text}} Submenu">
{{>_subnav-header}}
<ul class="nsw-subnavigation__list">
{{#each subnav}}
Expand All @@ -11,7 +11,7 @@
</svg>
{{/if}}
</a>
<div class="nsw-subnavigation" id="{{id}}-subnav" role="region" aria-label="{{text}} Submenu">
<div class="nsw-subnavigation" id="subnav-{{id}}" role="region" aria-label="{{text}} Submenu">
{{>_subnav-header}}
<ul class="nsw-subnavigation__list">
{{#each subnav}}
Expand Down
4 changes: 2 additions & 2 deletions src/components/main-navigation/_subnav-header.hbs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<div class="nsw-subnavigation__header">
<button type="button" class="nsw-subnavigation__back-btn js-close-subnav" aria-controls="{{id}}-subnav" aria-expanded="true">
<button type="button" class="nsw-subnavigation__back-btn js-close-subnav" aria-controls="subnav-{{id}}" aria-expanded="true">
<svg class="nsw-icon nsw-icon--rotate-180" focusable="false" aria-hidden="true">
<use xlink:href="#chevron"></use>
</svg>
<span>Back<span class="sr-only"> to {{text}}</span></span>
<span>Back<span class="sr-only"> to previous menu</span></span>
</button>

<button type="button" class="nsw-navigation__close js-close-navigation" aria-expanded="true">
Expand Down
94 changes: 60 additions & 34 deletions src/components/main-navigation/main-navigation.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
getFocusableElement, trapTabKey, whichTransitionEvent, getFocusableElementImmediate,
trapTabKey, whichTransitionEvent, getFocusableElementBySelector,
} from '../../global/scripts/helpers/utilities'

class Navigation {
Expand All @@ -16,34 +16,53 @@ class Navigation {
this.mobileShowMainTransitionEndEvent = (e) => this.mobileShowMainNav(e)
this.mobileHideMainTransitionEndEvent = (e) => this.mobileHideMainNav(e)
this.showSubNavTransitionEndEvent = (e) => this.showSubNav(e)
this.mobileTrapTabKeyEvent = (e) => trapTabKey(e, this.mainNavElement)
this.mobileTrapTabKeyEvent = (e) => this.mobileMainNavTrapTabs(e)
this.mobileSubNavTrapTabKeyEvent = (e) => this.trapkeyEventStuff(e)
this.desktopButtonClickEvent = (e) => this.buttonClickDesktop(e)
this.desktopButtonKeydownEvent = (e) => this.buttonKeydownDesktop(e)
this.checkFocusEvent = (e) => this.checkIfContainsFocus(e)
this.escapeCloseEvent = (e) => this.escapeClose(e)
this.openSubNavElements = []
this.breakpoint = window.matchMedia('(min-width: 48em)')
this.body = document.body
}

init() {
if (this.mainNavElement) {
this.setUpNavControls()
this.setUpMobileControls()
// this.responsiveCheck(this.breakpoint)
// this.breakpoint.addListener((e) => this.responsiveCheck(e))
this.responsiveCheck(this.breakpoint)
this.breakpoint.addListener((e) => this.responsiveCheck(e))
}
}

// responsiveCheck({ matches }) {
// if (matches) {
// // this.teardownMobileNav()
// // this.setUpDesktopNav()
// } else {
// this.setUpMobileNav()
// // this.teardownDesktopNav()
// }
// }
responsiveCheck(e) {
let megaMenuListItems = []
if (e.matches) {
megaMenuListItems = [].slice.call(this.mainNavElement.querySelectorAll('.nsw-navigation__list > li'))
this.body.classList.remove('navigation-open')
} else {
megaMenuListItems = [].slice.call(this.mainNavElement.querySelectorAll('li'))
}
this.tearDownNavControls()
this.setUpNavControls(megaMenuListItems)
}

tearDownNavControls() {
if (this.isMegaMenuElement) {
const listItems = [].slice.call(this.mainNavElement.querySelectorAll('li'))
listItems.forEach((item) => {
const submenu = item.querySelector('[id^=subnav-]')
const link = item.querySelector('a')
if (submenu) {
link.removeAttribute('role')
link.removeAttribute('aria-expanded')
link.removeAttribute('aria-controls')
link.removeEventListener('click', this.desktopButtonClickEvent, false)
link.removeEventListener('keydown', this.desktopButtonKeydownEvent, false)
}
})
}
}

setUpMobileControls() {
this.openNavButton.addEventListener('click', this.mobileToggleMainNavEvent, false)
Expand All @@ -52,20 +71,20 @@ class Navigation {
element.addEventListener('click', this.mobileToggleMainNavEvent, false)
})

this.mainNavElement.addEventListener('keydown', this.mobileTrapTabKeyEvent, false)

this.closeSubnavButtons.forEach((element) => {
element.addEventListener('click', this.mobileToggleSubnavEvent, false)
})
}

setUpNavControls() {
if (this.isMegaMenuElement) {
const tempListItems = this.mainNavElement.querySelectorAll('li')
const megaMenuListItems = Array.prototype.slice.call(tempListItems)
mobileMainNavTrapTabs(e) {
const elemObj = getFocusableElementBySelector(this.mainNavElement.id, ['> div button', '> ul > li > a'])
trapTabKey(e, elemObj)
}

megaMenuListItems.forEach((item) => {
const submenu = item.querySelector('[id$=-subnav]')
setUpNavControls(listItems) {
if (this.isMegaMenuElement) {
listItems.forEach((item) => {
const submenu = item.querySelector('[id^=subnav-]')
const link = item.querySelector('a')
if (submenu) {
link.setAttribute('role', 'button')
Expand All @@ -81,11 +100,11 @@ class Navigation {

mobileShowMainNav({ propertyName }) {
if (!propertyName === 'transform') return
console.log(getFocusableElementImmediate(this.mainNavElement))
getFocusableElement(this.mainNavElement).all[1].focus()
getFocusableElementBySelector(this.mainNavElement.id, ['> div button', '> ul > li > a']).all[1].focus()
this.mainNavElement.classList.add('is-open')
this.mainNavElement.classList.remove('is-opening')
this.mainNavElement.removeEventListener(this.transitionEvent, this.mobileShowMainTransitionEndEvent, false)
this.mainNavElement.addEventListener('keydown', this.mobileTrapTabKeyEvent, false)
}

mobileHideMainNav({ propertyName }) {
Expand All @@ -101,16 +120,19 @@ class Navigation {
this.openSubNavElements.pop()
}
this.mainNavElement.removeEventListener(this.transitionEvent, this.mobileHideMainTransitionEndEvent, false)
this.mainNavElement.removeEventListener('keydown', this.mobileTrapTabKeyEvent, false)
}

mobileToggleMainNav(e) {
const { currentTarget } = e
const isExpanded = currentTarget.getAttribute('aria-expanded') === 'true'
if (isExpanded) {
this.body.classList.remove('navigation-open')
this.openNavButton.focus()
this.mainNavElement.classList.add('is-closing')
this.mainNavElement.addEventListener(this.transitionEvent, this.mobileHideMainTransitionEndEvent, false)
} else {
this.body.classList.add('navigation-open')
this.mainNavElement.classList.add('is-opening')
this.mainNavElement.addEventListener(this.transitionEvent, this.mobileShowMainTransitionEndEvent, false)
}
Expand All @@ -123,19 +145,22 @@ class Navigation {
}

buttonKeydownDesktop(e) {
this.saveElements(e)
if (e.key === ' ' || e.key === 'Enter' || e.key === 'Spacebar') {
this.saveElements(e)
this.toggleSubnavDesktop()
e.preventDefault()
}
}

escapeClose(e) {
const { isExpanded, link } = this.whichSubNavLatest()
if (e.key === 'Escape' && isExpanded) {
this.toggleSubnavDesktop(true)
e.preventDefault()
link.focus()
if (e.key === 'Escape') {
const { link } = this.whichSubNavLatest()
const isExpanded = link.getAttribute('aria-expanded') === 'true'
if (isExpanded) {
this.toggleSubnavDesktop(true)
e.preventDefault()
link.focus()
}
}
}

Expand All @@ -144,7 +169,6 @@ class Navigation {
const temp = {
submenu: document.getElementById(currentTarget.getAttribute('aria-controls')),
link: currentTarget,
isExpanded: currentTarget.getAttribute('aria-expanded') === 'true',
linkParent: currentTarget.parentNode,
}

Expand All @@ -154,7 +178,7 @@ class Navigation {
showSubNav({ propertyName }) {
const { submenu } = this.whichSubNavLatest()
if (!propertyName === 'transform') return
getFocusableElement(submenu).all[2].focus()
getFocusableElementBySelector(submenu.id, ['> div button', '> h2 a', '> ul > li > a']).all[2].focus()
submenu.removeEventListener(this.transitionEvent, this.showSubNavTransitionEndEvent, false)
}

Expand Down Expand Up @@ -186,7 +210,8 @@ class Navigation {
}

toggleSubnavDesktop() {
const { isExpanded } = this.whichSubNavLatest()
const { link } = this.whichSubNavLatest()
const isExpanded = link.getAttribute('aria-expanded') === 'true'
if (isExpanded) {
this.closeSubnav()
} else {
Expand All @@ -209,7 +234,8 @@ class Navigation {

trapkeyEventStuff(e) {
const { submenu } = this.whichSubNavLatest()
trapTabKey(e, submenu)
const elemObj = getFocusableElementBySelector(submenu.id, ['> div button', '> ul > li > a'])
trapTabKey(e, elemObj)
}
}

Expand Down
Loading

0 comments on commit d1845b3

Please sign in to comment.