From e8bf27e5349f3e7c4d4917d242a310739fca2983 Mon Sep 17 00:00:00 2001 From: Jacob Korf Date: Tue, 17 Oct 2023 10:37:16 -0500 Subject: [PATCH 1/2] initial mobile menu commit --- boulder_base.libraries.yml | 11 ++- css/style.css | 6 ++ css/ucb-footer-menu-region.css | 9 ++ css/ucb-menu.css | 97 +++++++++++++++++++ css/ucb-secondary-menu-region.css | 2 +- js/ucb-access-menu.min.js | 2 + js/ucb-menu.js | 23 +++++ templates/navigation/menu--main.html.twig | 9 +- .../regions/region--secondary-menu.html.twig | 7 +- 9 files changed, 160 insertions(+), 6 deletions(-) create mode 100644 css/ucb-menu.css create mode 100644 js/ucb-access-menu.min.js create mode 100644 js/ucb-menu.js diff --git a/boulder_base.libraries.yml b/boulder_base.libraries.yml index 9f2f5c23..a9c1c8c1 100644 --- a/boulder_base.libraries.yml +++ b/boulder_base.libraries.yml @@ -408,4 +408,13 @@ ucb-people-list-block: js/ucb-people-list-block.js: {} css: theme: - css/block/ucb-people-list-block.css: {} \ No newline at end of file + css/block/ucb-people-list-block.css: {} + +ucb-menu: + version: 1.x + js: + js/ucb-menu.js: {} + js/ucb-access-menu.min.js: {} + css: + theme: + css/ucb-menu.css: {} \ No newline at end of file diff --git a/css/style.css b/css/style.css index 5895ada3..7c655767 100644 --- a/css/style.css +++ b/css/style.css @@ -235,6 +235,12 @@ align-items: center; } +@media only screen and (max-width: 600px) { + .ucb-main-nav-continer { + flex-direction: column; + } +} + /*********** Main Menu **************/ ul.ucb-main-menu.nav { flex-grow: 1; diff --git a/css/ucb-footer-menu-region.css b/css/ucb-footer-menu-region.css index 7de1273e..ee5ba967 100644 --- a/css/ucb-footer-menu-region.css +++ b/css/ucb-footer-menu-region.css @@ -17,3 +17,12 @@ color: var(--ucb-gold); background-color: transparent; } + + +@media only screen and (max-width: 600px) { + .ucb-footer-menu-region { + display: none; + } + + } + \ No newline at end of file diff --git a/css/ucb-menu.css b/css/ucb-menu.css new file mode 100644 index 00000000..6e9ee713 --- /dev/null +++ b/css/ucb-menu.css @@ -0,0 +1,97 @@ +#example-toggle { + display: none; +} + +.ucb-mobile-footer-menu { + display: none; +} + +@media only screen and (max-width: 600px) { + .ucb-primary-menu-region .ucb-primary-menu-region-container, + .ucb-secondary-menu-region .ucb-secondary-menu-region-container { + padding-left: 0; + padding-right: 0; + } + .ucb-main-nav-continer.ucb-secondary-menu-position-above { + flex-direction: column; + } + .ucb-main-nav-continer.ucb-secondary-menu-position-above .ucb-secondary-menu-region .menu-item a { + color: black; + padding-top: 8px; + padding-bottom: 8px; + padding-left: 16px; + line-height: 2rem; + margin-left: 2px; + } + .ucb-main-nav-continer.ucb-secondary-menu-position-above .ucb-secondary-menu-region ≈, .ucb-main-nav-continer.ucb-secondary-menu-position-above .ucb-secondary-menu-region .ucb-menu { + gap: 0; + } + .ucb-main-nav-continer.ucb-secondary-menu-position-above .ucb-secondary-menu-region { + background-color: white; + } + .ucb-secondary-menu-region { + width: 100%; + } + #example-toggle { + display: block; + max-width: 100px; + font-size: 20px; + margin-left: auto; + } + .ucb-menu, + .ucb-primary-menu-region { + width: 100%; + } + .ucb-menu.hide, + .ucb-main-menu.hide { + display: none; + } + .ucb-menu.open, + .ucb-main-menu.open { + display: flex; + flex-direction: column; + } + .ucb-menu .menu-item, + .main-menu-item { + border-bottom: 1px solid lightgrey; + } + .ucb-menu.open .menu-item a, + .ucb-main-menu.open .main-menu-item a { + font-weight: 300; + font-size: 16px; + padding-left: 16px; + border-bottom: 2px solid transparent; + } + .ucb-menu .menu-item.active, + .main-menu-item.active { + font-weight: 600; + color: #000; + background-color: #cfb87c; + border-bottom: 1px solid #cfb87c; + } + .ucb-menu.open .menu-item.active a, + .ucb-main-menu.open li.main-menu-item.active a { + border-bottom: 2px solid transparent; + } + + .ucb-mobile-footer-menu { + display: flex; + } + .ucb-main-nav-continer.ucb-secondary-menu-position-inline .ucb-secondary-menu-region .ucb-menu { + gap: 0; + } + .ucb-main-nav-continer.ucb-secondary-menu-position-above .ucb-secondary-menu-region .menu-item a:hover, + .ucb-main-nav-continer.ucb-secondary-menu-position-inline .ucb-secondary-menu-region .menu-item a:hover { + border-bottom: 2px solid black; + color: black; + } + + .ucb-main-nav-continer.ucb-secondary-menu-position-above .ucb-secondary-menu-region .menu-item:not(:active) a:hover, + .ucb-main-nav-continer.ucb-secondary-menu-position-inline .ucb-secondary-menu-region .menu-item:not(:active) a:hover { + background-color: white; + } + .ucb-main-nav-continer.ucb-secondary-menu-position-inline .ucb-secondary-menu-region .menu-item a { + margin: 0; + line-height: 2rem; + } +} diff --git a/css/ucb-secondary-menu-region.css b/css/ucb-secondary-menu-region.css index 18bd9c7f..11d9448d 100644 --- a/css/ucb-secondary-menu-region.css +++ b/css/ucb-secondary-menu-region.css @@ -1,6 +1,6 @@ .ucb-secondary-menu-region { display: flex; - flex-direction: row; + flex-direction: column; } .ucb-secondary-menu-region .ucb-menu { diff --git a/js/ucb-access-menu.min.js b/js/ucb-access-menu.min.js new file mode 100644 index 00000000..98689b6c --- /dev/null +++ b/js/ucb-access-menu.min.js @@ -0,0 +1,2 @@ +var AccessibleMenu=function(){"use strict";function e(e,t){try{if("object"!=typeof t){throw new TypeError(`AccessibleMenu: Elements given to isValidInstance() must be inside of an object. ${typeof t} given.`)}for(const n in t)if(!(t[n]instanceof e)){const s=typeof t[n];throw new TypeError(`AccessibleMenu: ${n} must be an instance of ${e.name}. ${s} given.`)}return!0}catch(e){return console.error(e),!1}}function t(e,t){try{if("object"!=typeof t){throw new TypeError(`AccessibleMenu: Values given to isValidType() must be inside of an object. ${typeof t} given.`)}for(const n in t){const s=typeof t[n];if(s!==e)throw new TypeError(`AccessibleMenu: ${n} must be a ${e}. ${s} given.`)}return!0}catch(e){return console.error(e),!1}}function n(e){try{if("object"!=typeof e){throw new TypeError(`AccessibleMenu: Values given to isCSSSelector() must be inside of an object. ${typeof e} given.`)}for(const t in e)try{if(null===e[t])throw new Error;document.querySelector(e[t])}catch(n){throw new TypeError(`AccessibleMenu: ${t} must be a valid CSS selector. "${e[t]}" given.`)}return!0}catch(e){return console.error(e),!1}}function s(e){try{if("object"!=typeof e||Array.isArray(e)){throw new TypeError(`AccessibleMenu: Values given to isValidClassList() must be inside of an object. ${typeof e} given.`)}for(const t in e){const s=typeof e[t];if("string"!==s){if(!Array.isArray(e[t]))throw new TypeError(`AccessibleMenu: ${t} must be a string or an array of strings. ${s} given.`);e[t].forEach((e=>{if("string"!=typeof e)throw new TypeError(`AccessibleMenu: ${t} must be a string or an array of strings. An array containing non-strings given.`)}))}else{const s={};s[t]=e[t],n(s)}}return!0}catch(e){return console.error(e),!1}}function l(e){try{if("object"!=typeof e){throw new TypeError(`AccessibleMenu: Values given to isValidHoverType() must be inside of an object. ${typeof e} given.`)}const t=["off","on","dynamic"];for(const n in e)if(!t.includes(e[n]))throw new TypeError(`AccessibleMenu: ${n} must be one of the following values: ${t.join(", ")}. "${e[n]}" given.`);return!0}catch(e){return console.error(e),!1}}class r{_dom={toggle:null,parent:null};_elements={controlledMenu:null,parentMenu:null};_open=!1;_expandEvent=new CustomEvent("accessibleMenuExpand",{bubbles:!0,detail:{toggle:this}});_collapseEvent=new CustomEvent("accessibleMenuCollapse",{bubbles:!0,detail:{toggle:this}});constructor(e){let{menuToggleElement:t,parentElement:n,controlledMenu:s,parentMenu:l=null}=e;this._dom.toggle=t,this._dom.parent=n,this._elements.controlledMenu=s,this._elements.parentMenu=l}initialize(){if(this.dom.toggle.setAttribute("aria-haspopup","true"),this.dom.toggle.setAttribute("aria-expanded","false"),function(n,s){if(t("string",{tagName:n})&&e(HTMLElement,s)){const e=n.toLowerCase();let t=!0;for(const n in s)s[n].tagName.toLowerCase()!==e&&(t=!1);return t}return!1}("button",{toggle:this.dom.toggle})||this.dom.toggle.setAttribute("role","button"),""===this.dom.toggle.id||""===this.elements.controlledMenu.dom.menu.id){const e=Math.random().toString(36).replace(/[^a-z]+/g,"").substr(0,10);let t=this.dom.toggle.innerText.replace(/[^a-zA-Z0-9\s]/g,""),n=e;!t.replace(/\s/g,"").length&&this.dom.toggle.getAttribute("aria-label")&&(t=this.dom.toggle.getAttribute("aria-label").replace(/[^a-zA-Z0-9\s]/g,"")),t.replace(/\s/g,"").length>0&&(t=t.toLowerCase().replace(/\s+/g,"-"),t.startsWith("-")&&(t=t.substring(1)),t.endsWith("-")&&(t=t.slice(0,-1)),n=`${t}-${n}`),this.dom.toggle.id=this.dom.toggle.id||`${n}-menu-button`,this.elements.controlledMenu.dom.menu.id=this.elements.controlledMenu.dom.menu.id||`${n}-menu`}this.elements.controlledMenu.dom.menu.setAttribute("aria-labelledby",this.dom.toggle.id),this.dom.toggle.setAttribute("aria-controls",this.elements.controlledMenu.dom.menu.id),this._collapse(!1)}get dom(){return this._dom}get elements(){return this._elements}get isOpen(){return this._open}set isOpen(e){t("boolean",{value:e}),this._open=e}_expand(){let e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];const{closeClass:t,openClass:n}=this.elements.controlledMenu;this.dom.toggle.setAttribute("aria-expanded","true"),""!==n&&("string"==typeof n?this.elements.controlledMenu.dom.menu.classList.add(n):this.elements.controlledMenu.dom.menu.classList.add(...n)),""!==t&&("string"==typeof t?this.elements.controlledMenu.dom.menu.classList.remove(t):this.elements.controlledMenu.dom.menu.classList.remove(...t)),e&&this.dom.toggle.dispatchEvent(this._expandEvent)}_collapse(){let e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];const{closeClass:t,openClass:n}=this.elements.controlledMenu;this.dom.toggle.setAttribute("aria-expanded","false"),""!==t&&("string"==typeof t?this.elements.controlledMenu.dom.menu.classList.add(t):this.elements.controlledMenu.dom.menu.classList.add(...t)),""!==n&&("string"==typeof n?this.elements.controlledMenu.dom.menu.classList.remove(n):this.elements.controlledMenu.dom.menu.classList.remove(...n)),e&&this.dom.toggle.dispatchEvent(this._collapseEvent)}open(){this.elements.controlledMenu.focusState="self",this._expand(),this.isOpen=!0}preview(){this.elements.parentMenu&&(this.elements.parentMenu.focusState="self"),this._expand(),this.isOpen=!0}close(){this.isOpen&&(this.elements.controlledMenu.currentChild=0,this.elements.controlledMenu.blur(),this.elements.parentMenu&&(this.elements.parentMenu.focusState="self"),this._collapse(),this.isOpen=!1)}toggle(){this.isOpen?this.close():this.open()}closeSiblings(){this.elements.parentMenu&&this.elements.parentMenu.elements.submenuToggles.forEach((e=>{e!==this&&e.close()}))}closeChildren(){this.elements.controlledMenu.elements.submenuToggles.forEach((e=>e.close()))}}class i{_dom={item:null,link:null};_elements={parentMenu:null,childMenu:null,toggle:null};_submenu=!1;constructor(e){let{menuItemElement:t,menuLinkElement:n,parentMenu:s,isSubmenuItem:l=!1,childMenu:r=null,toggle:i=null}=e;this._dom.item=t,this._dom.link=n,this._elements.parentMenu=s,this._elements.childMenu=r,this._elements.toggle=i,this._submenu=l}initialize(){}get dom(){return this._dom}get elements(){return this._elements}get isSubmenuItem(){return this._submenu}focus(){this.elements.parentMenu.shouldFocus&&this.dom.link.focus()}blur(){this.elements.parentMenu.shouldFocus&&this.dom.link.blur()}}function o(e){try{const t=e.key||e.keyCode,n={Enter:"Enter"===t||13===t,Space:" "===t||"Spacebar"===t||32===t,Escape:"Escape"===t||"Esc"===t||27===t,ArrowUp:"ArrowUp"===t||"Up"===t||38===t,ArrowRight:"ArrowRight"===t||"Right"===t||39===t,ArrowDown:"ArrowDown"===t||"Down"===t||40===t,ArrowLeft:"ArrowLeft"===t||"Left"===t||37===t,Home:"Home"===t||36===t,End:"End"===t||35===t,Character:isNaN(t)&&!!t.match(/^[a-zA-Z]{1}$/),Tab:"Tab"===t||9===t,Asterisk:"*"===t||56===t};return Object.keys(n).find((e=>!0===n[e]))||""}catch(e){return""}}function u(e){e.preventDefault(),e.stopPropagation()}class h{_MenuType=h;_MenuItemType=i;_MenuToggleType=r;_dom={menu:null,menuItems:[],submenuItems:[],submenuToggles:[],submenus:[],controller:null,container:null};_selectors={menuItems:"",menuLinks:"",submenuItems:"",submenuToggles:"",submenus:""};_elements={menuItems:[],submenuToggles:[],controller:null,parentMenu:null,rootMenu:null};_openClass="show";_closeClass="hide";_root=!0;_currentChild=0;_focusState="none";_currentEvent="none";_hoverType="off";_hoverDelay=250;constructor(e){let{menuElement:t,menuItemSelector:n="li",menuLinkSelector:s="a",submenuItemSelector:l="",submenuToggleSelector:r="a",submenuSelector:i="ul",controllerElement:o=null,containerElement:u=null,openClass:h="show",closeClass:m="hide",isTopLevel:c=!0,parentMenu:a=null,hoverType:d="off",hoverDelay:p=250}=e;this._dom.menu=t,this._dom.controller=o,this._dom.container=u,this._selectors.menuItems=n,this._selectors.menuLinks=s,this._selectors.submenuItems=l,this._selectors.submenuToggles=r,this._selectors.submenus=i,this._elements.menuItems=[],this._elements.submenuToggles=[],this._elements.controller=null,this._elements.parentMenu=a,this._elements.rootMenu=c?this:null,this._openClass=h||"",this._closeClass=m||"",this._root=c,this._hoverType=d,this._hoverDelay=p}initialize(){if(!this._validate())throw new Error("AccesibleMenu: cannot initialize menu. See other error messages for more information.");if(null===this.elements.rootMenu&&this._findRootMenu(this),this._setDOMElements(),this.isTopLevel&&this.dom.controller&&this.dom.container){const e=new this._MenuToggleType({menuToggleElement:this.dom.controller,parentElement:this.dom.container,controlledMenu:this});this._elements.controller=e}this._createChildElements()}get dom(){return this._dom}get selectors(){return this._selectors}get elements(){return this._elements}get isTopLevel(){return this._root}get openClass(){return this.isTopLevel?this._openClass:this.elements.rootMenu.openClass}get closeClass(){return this.isTopLevel?this._closeClass:this.elements.rootMenu.closeClass}get currentChild(){return this._currentChild}get focusState(){return this._focusState}get currentEvent(){return this._currentEvent}get currentMenuItem(){return this.elements.menuItems[this.currentChild]}get hoverType(){return this._root?this._hoverType:this.elements.rootMenu.hoverType}get hoverDelay(){return this._root?this._hoverDelay:this.elements.rootMenu.hoverDelay}get shouldFocus(){let e=!1;return"keyboard"!==this.currentEvent&&"character"!==this.currentEvent||(e=!0),"mouse"===this.currentEvent&&"dynamic"===this.hoverType&&(e=!0),e}set openClass(e){s({openClass:e}),this._openClass!==e&&(this._openClass=e)}set closeClass(e){s({closeClass:e}),this._closeClass!==e&&(this._closeClass=e)}set currentChild(e){function n(e){if(["mouse","character"].includes(e.currentEvent)&&e.elements.parentMenu){let t=0,n=!1;for(;!n&&t=this.elements.menuItems.length?(this._currentChild=this.elements.menuItems.length-1,n(this)):this.focusChild!==e&&(this._currentChild=e,n(this))}set focusState(e){!function(e){try{if("object"!=typeof e)throw new TypeError(`AccessibleMenu: Values given to isValidState() must be inside of an object. ${typeof e} given.`);const t=["none","self","child"];for(const n in e)if(!t.includes(e[n]))throw new TypeError(`AccessibleMenu: ${n} must be one of the following values: ${t.join(", ")}. "${e[n]}" given.`);return!0}catch(e){return console.error(e),!1}}({value:e}),this._focusState!==e&&(this._focusState=e),this.elements.submenuToggles.length>0&&("self"===e||"none"===e)&&this.elements.submenuToggles.forEach((e=>{e.elements.controlledMenu.focusState="none"})),!this.elements.parentMenu||"self"!==e&&"child"!==e||(this.elements.parentMenu.focusState="child")}set currentEvent(e){!function(e){try{if("object"!=typeof e)throw new TypeError(`AccessibleMenu: Values given to isValidEvent() must be inside of an object. ${typeof e} given.`);const t=["none","mouse","keyboard","character"];for(const n in e)if(!t.includes(e[n]))throw new TypeError(`AccessibleMenu: ${n} must be one of the following values: ${t.join(", ")}. "${e[n]}" given.`);return!0}catch(e){return console.error(e),!1}}({value:e}),this._currentEvent!==e&&(this._currentEvent=e,this.elements.submenuToggles.length>0&&this.elements.submenuToggles.forEach((t=>{t.elements.controlledMenu.currentEvent=e})))}set hoverType(e){l({value:e}),this._hoverType!==e&&(this._hoverType=e)}set hoverDelay(e){t("number",{value:e}),this._hoverDelay!==e&&(this._hoverDelay=e)}_validate(){let r=!0;return null!==this._dom.container||null!==this._dom.controller?e(HTMLElement,{menuElement:this._dom.menu,controllerElement:this._dom.controller,containerElement:this._dom.container})||(r=!1):e(HTMLElement,{menuElement:this._dom.menu})||(r=!1),""!==this._selectors.submenuItems?n({menuItemSelector:this._selectors.menuItems,menuLinkSelector:this._selectors.menuLinks,submenuItemSelector:this._selectors.submenuItems,submenuToggleSelector:this._selectors.submenuToggles,submenuSelector:this._selectors.submenus})||(r=!1):n({menuItemSelector:this._selectors.menuItems,menuLinkSelector:this._selectors.menuLinks})||(r=!1),""===this._openClass||s({openClass:this._openClass})||(r=!1),""===this._closeClass||s({closeClass:this._closeClass})||(r=!1),t("boolean",{isTopLevel:this._root})||(r=!1),null===this._elements.parentMenu||e(h,{parentMenu:this._elements.parentMenu})||(r=!1),l({hoverType:this._hoverType})||(r=!1),t("number",{hoverDelay:this._hoverDelay})||(r=!1),r}_setDOMElementType(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.dom.menu,s=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];if("string"!=typeof this.selectors[t])throw new Error(`AccessibleMenu: "${t}" is not a valid element type within the menu.`);{if(!Array.isArray(this.dom[t]))throw new Error(`AccessibleMenu: The "${t}" element cannot be set through _setDOMElementType.`);n!==this.dom.menu&&e(HTMLElement,{base:n});const l=Array.from(n.querySelectorAll(this.selectors[t])).filter((e=>e.parentElement===n));this._dom[t]=s?l:[...this._dom[t],...l]}}_resetDOMElementType(e){if(void 0===this.dom[e])throw new Error(`AccessibleMenu: "${e}" is not a valid element type within the menu.`);if(!Array.isArray(this.dom[e]))throw new Error(`AccessibleMenu: The "${e}" element cannot be reset through _resetDOMElementType.`);this._dom[e]=[]}_setDOMElements(){this._setDOMElementType("menuItems"),""!==this.selectors.submenuItems&&(this._setDOMElementType("submenuItems"),this._resetDOMElementType("submenuToggles"),this._resetDOMElementType("submenus"),this.dom.submenuItems.forEach((e=>{this._setDOMElementType("submenuToggles",e,!1),this._setDOMElementType("submenus",e,!1)})))}_findRootMenu(e){if(e.isTopLevel)this._elements.rootMenu=e;else{if(null===e.elements.parentMenu)throw new Error("Cannot find root menu.");this._findRootMenu(e.elements.parentMenu)}}_createChildElements(){this.dom.menuItems.forEach((e=>{let t;if(this.dom.submenuItems.includes(e)){const n=e.querySelector(this.selectors.submenuToggles),s=e.querySelector(this.selectors.submenus),l=new this._MenuType({menuElement:s,menuItemSelector:this.selectors.menuItems,menuLinkSelector:this.selectors.menuLinks,submenuItemSelector:this.selectors.submenuItems,submenuToggleSelector:this.selectors.submenuToggles,submenuSelector:this.selectors.submenus,openClass:this.openClass,closeClass:this.closeClass,isTopLevel:!1,parentMenu:this,hoverType:this.hoverType,hoverDelay:this.hoverDelay}),r=new this._MenuToggleType({menuToggleElement:n,parentElement:e,controlledMenu:l,parentMenu:this});this._elements.submenuToggles.push(r),t=new this._MenuItemType({menuItemElement:e,menuLinkElement:n,parentMenu:this,isSubmenuItem:!0,childMenu:l,toggle:r})}else{const n=e.querySelector(this.selectors.menuLinks);t=new this._MenuItemType({menuItemElement:e,menuLinkElement:n,parentMenu:this})}this._elements.menuItems.push(t)}))}_handleFocus(){this.elements.menuItems.forEach(((e,t)=>{e.dom.link.addEventListener("focus",(()=>{this.focusState="self",this.currentChild=t}))}))}_handleClick(){function e(e,t,n){u(n),t.toggle(),t.isOpen&&(e.focusState="self",t.elements.controlledMenu.focusState="none")}this.elements.menuItems.forEach(((t,n)=>{t.dom.link.addEventListener("pointerdown",(()=>{this.currentEvent="mouse",this.elements.rootMenu.blurChildren(),this.focusChild(n)}),{passive:!0}),t.isSubmenuItem&&t.elements.toggle.dom.toggle.addEventListener("pointerup",(n=>{this.currentEvent="mouse",e(this,t.elements.toggle,n)}))})),this.isTopLevel&&this.elements.controller&&this.elements.controller.dom.toggle.addEventListener("pointerup",(t=>{this.currentEvent="mouse",e(this,this.elements.controller,t)}))}_handleHover(){this.elements.menuItems.forEach(((e,t)=>{e.dom.link.addEventListener("pointerenter",(n=>{if("pen"!==n.pointerType&&"touch"!==n.pointerType)if("on"===this.hoverType)this.currentEvent="mouse",this.currentChild=t,e.isSubmenuItem&&e.elements.toggle.preview();else if("dynamic"===this.hoverType){const n=this.elements.submenuToggles.some((e=>e.isOpen));this.currentChild=t,this.isTopLevel&&"none"===this.focusState||(this.currentEvent="mouse",this.focusCurrentChild()),!e.isSubmenuItem||this.isTopLevel&&!n||(this.currentEvent="mouse",e.elements.toggle.preview())}})),e.isSubmenuItem&&e.dom.item.addEventListener("pointerleave",(t=>{"pen"!==t.pointerType&&"touch"!==t.pointerType&&("on"===this.hoverType?this.hoverDelay>0?setTimeout((()=>{this.currentEvent="mouse",e.elements.toggle.close()}),this.hoverDelay):(this.currentEvent="mouse",e.elements.toggle.close()):"dynamic"===this.hoverType&&(this.isTopLevel||(this.hoverDelay>0?setTimeout((()=>{this.currentEvent="mouse",e.elements.toggle.close(),this.focusCurrentChild()}),this.hoverDelay):(this.currentEvent="mouse",e.elements.toggle.close(),this.focusCurrentChild()))))}))}))}_handleKeydown(){this.isTopLevel&&this.elements.controller&&this.elements.controller.dom.toggle.addEventListener("keydown",(e=>{this.currentEvent="keyboard";const t=o(e);"Space"!==t&&"Enter"!==t||u(e)}))}_handleKeyup(){this.isTopLevel&&this.elements.controller&&this.elements.controller.dom.toggle.addEventListener("keyup",(e=>{this.currentEvent="keyboard";const t=o(e);"Space"!==t&&"Enter"!==t||(u(e),this.elements.controller.toggle(),this.elements.controller.isOpen&&this.focusFirstChild())}))}focus(){this.focusState="self",this.shouldFocus&&this.dom.menu.focus()}blur(){this.focusState="none",this.shouldFocus&&this.dom.menu.blur()}focusCurrentChild(){this.focusState="self",-1!==this.currentChild&&this.currentMenuItem.focus()}focusChild(e){this.blurCurrentChild(),this.currentChild=e,this.focusCurrentChild()}focusFirstChild(){this.focusChild(0)}focusLastChild(){this.focusChild(this.elements.menuItems.length-1)}focusNextChild(){this.currentChild0?this.focusChild(this.currentChild-1):this.focusCurrentChild()}blurCurrentChild(){this.focusState="none",-1!==this.currentChild&&this.currentMenuItem.blur()}focusController(){this.dom.controller&&(this.shouldFocus&&this.dom.controller.focus(),this.focusState="none")}focusContainer(){this.dom.container&&(this.shouldFocus&&this.dom.container.focus(),this.focusState="none")}closeChildren(){this.elements.submenuToggles.forEach((e=>e.close()))}blurChildren(){this.elements.menuItems.forEach((e=>{e.blur(),e.isSubmenuItem&&e.elements.childMenu.blurChildren()}))}}class m extends i{constructor(e){let{menuItemElement:t,menuLinkElement:n,parentMenu:s,isSubmenuItem:l=!1,childMenu:r=null,toggle:i=null,initialize:o=!0}=e;super({menuItemElement:t,menuLinkElement:n,parentMenu:s,isSubmenuItem:l,childMenu:r,toggle:i}),o&&this.initialize()}}class c extends r{constructor(e){let{menuToggleElement:t,parentElement:n,controlledMenu:s,parentMenu:l=null,initialize:r=!0}=e;super({menuToggleElement:t,parentElement:n,controlledMenu:s,parentMenu:l}),r&&this.initialize()}open(){this.closeSiblings(),super.open()}preview(){this.closeSiblings(),super.preview()}close(){this.isOpen&&this.closeChildren(),super.close()}}class a extends h{_MenuType=a;_MenuItemType=m;_MenuToggleType=c;_currentChild=-1;_optionalSupport=!1;constructor(e){let{menuElement:t,menuItemSelector:n="li",menuLinkSelector:s="a",submenuItemSelector:l="",submenuToggleSelector:r="a",submenuSelector:i="ul",controllerElement:o=null,containerElement:u=null,openClass:h="show",closeClass:m="hide",isTopLevel:c=!0,parentMenu:a=null,hoverType:d="off",hoverDelay:p=250,optionalKeySupport:g=!1,initialize:M=!0}=e;super({menuElement:t,menuItemSelector:n,menuLinkSelector:s,submenuItemSelector:l,submenuToggleSelector:r,submenuSelector:i,controllerElement:o,containerElement:u,openClass:h,closeClass:m,isTopLevel:c,parentMenu:a,hoverType:d,hoverDelay:p}),this._optionalSupport=g,M&&this.initialize()}initialize(){try{super.initialize(),this._handleFocus(),this._handleClick(),this._handleHover(),this._handleKeydown(),this._handleKeyup()}catch(e){console.error(e)}}get optionalKeySupport(){return this.isTopLevel?this._optionalSupport:this.elements.rootMenu.optionalKeySupport}set optionalKeySupport(e){t("boolean",{optionalKeySupport:e}),this._optionalSupport=e}_validate(){let e=super._validate();return t("boolean",{optionalKeySupport:this._optionalSupport})||(e=!1),e}_handleClick(){super._handleClick(),document.addEventListener("pointerup",(e=>{"none"!==this.focusState&&(this.currentEvent="mouse",this.dom.menu.contains(e.target)||!this.dom.menu===e.target||(this.closeChildren(),this.blur(),this.elements.controller&&this.elements.controller.close()))}))}_handleKeydown(){super._handleKeydown(),this.dom.menu.addEventListener("keydown",(e=>{this.currentEvent="keyboard";const t=o(e);if("self"===this.focusState){const n=["Space","Enter"],s=["Escape"],l=["Escape"];if(this.optionalKeySupport){["ArrowUp","ArrowRight","ArrowDown","ArrowLeft","Home","End"].includes(t)&&u(e)}else(this.currentMenuItem.isSubmenuItem&&n.includes(t)||this.elements.controller&&s.includes(t)||this.elements.parentMenu&&l.includes(t))&&u(e)}}))}_handleKeyup(){super._handleKeyup(),this.dom.menu.addEventListener("keyup",(e=>{this.currentEvent="keyboard";const t=o(e);if("self"===this.focusState)if("Space"===t||"Enter"===t)this.currentMenuItem.isSubmenuItem?(u(e),this.currentMenuItem.elements.toggle.isOpen?this.currentMenuItem.elements.toggle.close():this.currentMenuItem.elements.toggle.preview()):this.currentMenuItem.dom.link.click();else if("Escape"===t){this.elements.submenuToggles.some((e=>e.isOpen))?(u(e),this.closeChildren()):this.elements.parentMenu?(u(e),this.elements.parentMenu.currentEvent=this.currentEvent,this.elements.parentMenu.closeChildren(),this.elements.parentMenu.focusCurrentChild()):this.isTopLevel&&this.elements.controller&&this.elements.controller.isOpen&&(this.elements.controller.close(),this.focusController())}else this.optionalKeySupport&&("ArrowDown"===t||"ArrowRight"===t?(u(e),this.currentMenuItem.isSubmenuItem&&this.currentMenuItem.elements.toggle.isOpen?(this.currentMenuItem.elements.childMenu.currentEvent="keyboard",this.currentMenuItem.elements.childMenu.focusFirstChild()):this.focusNextChild()):"ArrowUp"===t||"ArrowLeft"===t?(u(e),this.focusPreviousChild()):"Home"===t?(u(e),this.focusFirstChild()):"End"===t&&(u(e),this.focusLastChild()))}))}}class d extends i{constructor(e){let{menuItemElement:t,menuLinkElement:n,parentMenu:s,isSubmenuItem:l=!1,childMenu:r=null,toggle:i=null,initialize:o=!0}=e;super({menuItemElement:t,menuLinkElement:n,parentMenu:s,isSubmenuItem:l,childMenu:r,toggle:i}),o&&this.initialize()}initialize(){super.initialize(),this.dom.item.setAttribute("role","none"),this.dom.link.setAttribute("role","menuitem"),this.dom.link.tabIndex=-1}focus(){super.focus(),this.elements.parentMenu.isTopLevel&&(this.dom.link.tabIndex=0)}blur(){super.blur(),this.elements.parentMenu.isTopLevel&&(this.dom.link.tabIndex=-1)}}class p extends r{constructor(e){let{menuToggleElement:t,parentElement:n,controlledMenu:s,parentMenu:l=null,initialize:r=!0}=e;super({menuToggleElement:t,parentElement:n,controlledMenu:s,parentMenu:l}),r&&this.initialize()}open(){this.closeSiblings(),super.open()}preview(){this.closeSiblings(),super.preview()}close(){this.isOpen&&this.closeChildren(),super.close()}}class g extends h{_MenuType=g;_MenuItemType=d;_MenuToggleType=p;constructor(e){let{menuElement:t,menuItemSelector:n="li",menuLinkSelector:s="a",submenuItemSelector:l="",submenuToggleSelector:r="a",submenuSelector:i="ul",controllerElement:o=null,containerElement:u=null,openClass:h="show",closeClass:m="hide",isTopLevel:c=!0,parentMenu:a=null,hoverType:d="off",hoverDelay:p=250,initialize:g=!0}=e;super({menuElement:t,menuItemSelector:n,menuLinkSelector:s,submenuItemSelector:l,submenuToggleSelector:r,submenuSelector:i,controllerElement:o,containerElement:u,openClass:h,closeClass:m,isTopLevel:c,parentMenu:a,hoverType:d,hoverDelay:p}),g&&this.initialize()}initialize(){try{super.initialize(),this.isTopLevel?this.dom.menu.setAttribute("role","menubar"):this.dom.menu.setAttribute("role","menu"),this._handleFocus(),this._handleClick(),this._handleHover(),this._handleKeydown(),this._handleKeyup(),this.isTopLevel&&(this.elements.menuItems[0].dom.link.tabIndex=0)}catch(e){console.error(e)}}_handleClick(){super._handleClick(),document.addEventListener("pointerup",(e=>{"none"!==this.focusState&&(this.currentEvent="mouse",this.dom.menu.contains(e.target)||!this.dom.menu===e.target||(this.closeChildren(),this.blur(),this.elements.controller&&this.elements.controller.close()))}))}_handleKeydown(){super._handleKeydown(),this.dom.menu.addEventListener("keydown",(e=>{this.currentEvent="keyboard";const t=o(e);if("Tab"===t&&("none"!==this.elements.rootMenu.focusState?(this.elements.rootMenu.blur(),this.elements.rootMenu.closeChildren()):this.elements.rootMenu.focus()),"Character"===t)u(e);else if(this.isTopLevel){if("self"===this.focusState){const n=["Space","Enter","ArrowDown","ArrowUp"],s=["Escape"];(["ArrowRight","ArrowLeft","Home","End"].includes(t)||this.currentMenuItem.isSubmenuItem&&n.includes(t)||this.elements.controller&&s.includes(t))&&u(e)}}else{const n=["Space","Enter"];(["Escape","ArrowRight","ArrowLeft","ArrowDown","ArrowUp","Home","End"].includes(t)||this.currentMenuItem.isSubmenuItem&&n.includes(t))&&u(e)}}))}_handleKeyup(){super._handleKeyup(),this.dom.menu.addEventListener("keyup",(e=>{this.currentEvent="keyboard";const t=o(e),{altKey:n,crtlKey:s,metaKey:l}=e;if("Character"!==t||(n||s||l))if(this.isTopLevel){if("self"===this.focusState)if("Space"===t||"Enter"===t)this.currentMenuItem.isSubmenuItem?(u(e),this.currentMenuItem.elements.childMenu.currentEvent="keyboard",this.currentMenuItem.elements.toggle.open(),requestAnimationFrame((()=>{this.currentMenuItem.elements.childMenu.focusFirstChild()}))):this.currentMenuItem.dom.link.click();else if("ArrowRight"===t){u(e);const t=this.currentMenuItem.isSubmenuItem&&this.currentMenuItem.elements.toggle.isOpen;this.focusNextChild(),t&&(this.currentMenuItem.isSubmenuItem?(this.currentMenuItem.elements.childMenu.currentEvent="keyboard",this.currentMenuItem.elements.toggle.preview()):this.closeChildren())}else if("ArrowLeft"===t){u(e);const t=this.currentMenuItem.isSubmenuItem&&this.currentMenuItem.elements.toggle.isOpen;this.focusPreviousChild(),t&&(this.currentMenuItem.isSubmenuItem?(this.currentMenuItem.elements.childMenu.currentEvent="keyboard",this.currentMenuItem.elements.toggle.preview()):this.closeChildren())}else if("ArrowDown"===t)this.currentMenuItem.isSubmenuItem&&(u(e),this.currentMenuItem.elements.childMenu.currentEvent="keyboard",this.currentMenuItem.elements.toggle.open(),requestAnimationFrame((()=>{this.currentMenuItem.elements.childMenu.focusFirstChild()})));else if("ArrowUp"===t)this.currentMenuItem.isSubmenuItem&&(u(e),this.currentMenuItem.elements.childMenu.currentEvent="keyboard",this.currentMenuItem.elements.toggle.open(),requestAnimationFrame((()=>{this.currentMenuItem.elements.childMenu.focusLastChild()})));else if("Home"===t)u(e),this.focusFirstChild();else if("End"===t)u(e),this.focusLastChild();else if("Escape"===t){this.elements.submenuToggles.some((e=>e.isOpen))?(u(e),this.closeChildren()):this.isTopLevel&&this.elements.controller&&this.elements.controller.isOpen&&(u(e),this.elements.controller.close(),this.focusController())}}else"Space"===t||"Enter"===t?this.currentMenuItem.isSubmenuItem?(u(e),this.currentMenuItem.elements.childMenu.currentEvent="keyboard",this.currentMenuItem.elements.toggle.open(),requestAnimationFrame((()=>{this.currentMenuItem.elements.childMenu.focusFirstChild()}))):this.currentMenuItem.dom.link.click():"Escape"===t?(u(e),this.elements.rootMenu.closeChildren(),this.elements.rootMenu.focusCurrentChild()):"ArrowRight"===t?this.currentMenuItem.isSubmenuItem?(u(e),this.currentMenuItem.elements.childMenu.currentEvent="keyboard",this.currentMenuItem.elements.toggle.open(),requestAnimationFrame((()=>{this.currentMenuItem.elements.childMenu.focusFirstChild()}))):(u(e),this.elements.rootMenu.closeChildren(),this.elements.rootMenu.focusNextChild(),this.elements.rootMenu.currentMenuItem.isSubmenuItem&&this.elements.rootMenu.currentMenuItem.elements.toggle.preview()):"ArrowLeft"===t?this.elements.parentMenu.currentMenuItem.isSubmenuItem&&(u(e),this.elements.parentMenu.currentMenuItem.elements.toggle.close(),this.elements.parentMenu.focusCurrentChild(),this.elements.parentMenu===this.elements.rootMenu&&(this.elements.rootMenu.closeChildren(),this.elements.rootMenu.focusPreviousChild(),this.elements.rootMenu.currentMenuItem.isSubmenuItem&&(this.elements.rootMenu.currentMenuItem.elements.childMenu.currentEvent="keyboard",this.elements.rootMenu.currentMenuItem.elements.toggle.preview()))):"ArrowDown"===t?(u(e),this.focusNextChild()):"ArrowUp"===t?(u(e),this.focusPreviousChild()):"Home"===t?(u(e),this.focusFirstChild()):"End"===t&&(u(e),this.focusLastChild());else u(e),this.elements.rootMenu.currentEvent="character",this.focusNextChildWithCharacter(e.key)}))}focusNextChild(){this.currentChild===this.elements.menuItems.length-1?this.focusFirstChild():this.focusChild(this.currentChild+1)}focusPreviousChild(){0===this.currentChild?this.focusLastChild():this.focusChild(this.currentChild-1)}focusNextChildWithCharacter(e){const t=e.toLowerCase();let n=this.currentChild+1,s=!1;for(;!s&&n{this.currentEvent="keyboard";const t=o(e);if("Tab"===t&&("none"!==this.elements.rootMenu.focusState?this.elements.rootMenu.blur():this.elements.rootMenu.focus()),"self"===this.focusState){const n=["Enter","ArrowRight"],s=["Escape"];(["Space","ArrowUp","ArrowDown","ArrowLeft","Asterisk","Home","End"].includes(t)||this.currentMenuItem.isSubmenuItem&&n.includes(t)||this.elements.controller&&s.includes(t))&&u(e)}}))}_handleKeyup(){super._handleKeyup(),this.dom.menu.addEventListener("keyup",(e=>{this.currentEvent="keyboard";const t=o(e),{altKey:n,crtlKey:s,metaKey:l}=e;if("Character"!==t||(n||s||l)){if("self"===this.focusState)if("Enter"===t||"Space"===t)u(e),this.currentMenuItem.isSubmenuItem?this.currentMenuItem.elements.toggle.isOpen?this.currentMenuItem.elements.toggle.close():this.currentMenuItem.elements.toggle.preview():this.currentMenuItem.dom.link.click();else if("Escape"===t)this.isTopLevel&&this.elements.controller&&this.elements.controller.isOpen&&(this.elements.controller.close(),this.focusController());else if("ArrowDown"===t)u(e),this.currentMenuItem.isSubmenuItem&&this.currentMenuItem.elements.toggle.isOpen?(this.blurCurrentChild(),this.currentMenuItem.elements.childMenu.currentEvent=this.currentEvent,this.currentMenuItem.elements.childMenu.focusFirstChild()):this.isTopLevel||this.currentChild!==this.elements.menuItems.length-1?this.focusNextChild():this.focusParentsNextChild();else if("ArrowUp"===t){u(e);const t=this.elements.menuItems[this.currentChild-1];t&&t.isSubmenuItem&&t.elements.toggle.isOpen?(this.blurCurrentChild(),this.currentChild=this.currentChild-1,this.currentMenuItem.elements.childMenu.currentEvent=this.currentEvent,this.focusChildsLastNode()):this.isTopLevel||0!==this.currentChild?this.focusPreviousChild():(this.blurCurrentChild(),this.elements.parentMenu.currentEvent=this.currentEvent,this.elements.parentMenu.focusCurrentChild())}else"ArrowRight"===t?this.currentMenuItem.isSubmenuItem&&(u(e),this.currentMenuItem.elements.toggle.isOpen?(this.blurCurrentChild(),this.currentMenuItem.elements.childMenu.currentEvent=this.currentEvent,this.currentMenuItem.elements.childMenu.focusFirstChild()):this.currentMenuItem.elements.toggle.preview()):"ArrowLeft"===t?(u(e),this.currentMenuItem.isSubmenuItem&&this.currentMenuItem.elements.toggle.isOpen?(this.currentMenuItem.elements.childMenu.blurCurrentChild(),this.currentMenuItem.elements.toggle.close()):this.isTopLevel||(this.blurCurrentChild(),this.elements.parentMenu.currentEvent=this.currentEvent,this.elements.parentMenu.focusCurrentChild())):"Home"===t?(u(e),this.blurCurrentChild(),this.elements.rootMenu.focusFirstChild()):"End"===t?(u(e),this.blurCurrentChild(),this.elements.rootMenu.focusLastNode()):"Asterisk"===t&&(u(e),this.openChildren())}else u(e),this.elements.rootMenu.currentEvent="character",this.focusNextNodeWithCharacter(e.key)}))}focusLastNode(){const e=this.elements.menuItems.length-1,t=this.elements.menuItems[e];t.isSubmenuItem&&t.elements.toggle.isOpen?(this.currentChild=e,t.elements.childMenu.currentEvent=this.currentEvent,t.elements.childMenu.focusLastNode()):this.focusLastChild()}openChildren(){this.elements.submenuToggles.forEach((e=>e.preview()))}focusNextNodeWithCharacter(e){const t=e.toLowerCase(),n=function e(t){let n=[];return t.elements.menuItems.forEach((t=>{n.push(t),t.isSubmenuItem&&t.elements.toggle.isOpen&&(n=[...n,...e(t.elements.toggle.elements.controlledMenu)])})),n}(this.elements.rootMenu),s=n.indexOf(this.currentMenuItem)+1,l=[...n.slice(s),...n.slice(0,s)];let r=0,i=!1;for(;!i&&r { + const mainMenu = new AccessibleMenu.DisclosureMenu({ + menuElement: document.querySelector("#ucb-main-menu"), + controllerElement: document.querySelector("#example-toggle"), + containerElement: document.querySelector("#ucb-main-menu-nav"), + openClass: "open", + }); + const secondaryWrapper = document.querySelector(".ucb-secondary-menu-region-container") + const secondaryMenu = new AccessibleMenu.DisclosureMenu({ + menuElement: document.getElementById("ucb-secondary-menu-region-container").getElementsByClassName("ucb-menu")[0], + controllerElement: document.querySelector("#example-toggle"), + containerElement: secondaryWrapper, + openClass: "open", + }); + + const footerMenu = new AccessibleMenu.DisclosureMenu({ + menuElement: document.getElementById("ucb-mobile-footer-menu").getElementsByClassName("ucb-menu")[0], + controllerElement: document.querySelector("#example-toggle"), + containerElement: secondaryWrapper, + openClass: "open", + }); +}); diff --git a/templates/navigation/menu--main.html.twig b/templates/navigation/menu--main.html.twig index 91543b5d..348e38ff 100755 --- a/templates/navigation/menu--main.html.twig +++ b/templates/navigation/menu--main.html.twig @@ -32,11 +32,15 @@ We call a macro which calls itself to render the full tree. @see http://twig.sensiolabs.org/doc/tags/macro.html #} + +{{ attach_library('boulder_base/ucb-menu') }} {{ menus.menu_links(items, attributes, 0) }} {% macro menu_links(items, attributes, menu_level) %} {% import _self as menus %} - {% if items %} - + {% if items %} + {% endif %} {% endmacro %} diff --git a/templates/regions/region--secondary-menu.html.twig b/templates/regions/region--secondary-menu.html.twig index 1bbb78e3..3d5ad786 100644 --- a/templates/regions/region--secondary-menu.html.twig +++ b/templates/regions/region--secondary-menu.html.twig @@ -13,9 +13,12 @@ */ #} {{ attach_library('boulder_base/ucb-secondary-menu-region') }} -
-
+
+
{% if ucb_secondary_menu_default_links %}{% include "@boulder_base/includes/ucb-header-secondary-menu.html.twig" %}{% endif %} {{ content }}
+
\ No newline at end of file From 56c7f0f996a1ce760edb32171cb05ff53ab1c81a Mon Sep 17 00:00:00 2001 From: Jacob Korf Date: Wed, 18 Oct 2023 10:05:51 -0500 Subject: [PATCH 2/2] updated button css --- css/ucb-menu.css | 5 ++++- templates/navigation/menu--main.html.twig | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/css/ucb-menu.css b/css/ucb-menu.css index 6e9ee713..6c6a3985 100644 --- a/css/ucb-menu.css +++ b/css/ucb-menu.css @@ -7,6 +7,9 @@ } @media only screen and (max-width: 600px) { + .ucb-mobile-menu-button-div { + line-height: 2em; + } .ucb-primary-menu-region .ucb-primary-menu-region-container, .ucb-secondary-menu-region .ucb-secondary-menu-region-container { padding-left: 0; @@ -35,7 +38,7 @@ #example-toggle { display: block; max-width: 100px; - font-size: 20px; + font-size: 2em; margin-left: auto; } .ucb-menu, diff --git a/templates/navigation/menu--main.html.twig b/templates/navigation/menu--main.html.twig index 348e38ff..55da9b1c 100755 --- a/templates/navigation/menu--main.html.twig +++ b/templates/navigation/menu--main.html.twig @@ -39,7 +39,9 @@ {% import _self as menus %} {% if items %}