@servicensw/drop-menu
Advanced tools
Comparing version 2.3.8 to 2.4.0
@@ -1,1 +0,1 @@ | ||
!function(){"use strict";function t(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}if(window.SNSW=window.SNSW||{},void 0===SNSW.Keyboard&&console.warn("SNSW.Keyboard has not been loaded. Keyboard navigation for the ".concat("Drop menu"," component will not function.")),!NodeList.prototype.forEach)throw new Error((t=>"Required polyfills are not loaded, the ".concat(t," component will not function properly in this browser."))("Drop menu"));SNSW.DropMenu=class{constructor(e,n){t(this,"closeMenu",()=>{this.button.setAttribute("aria-expanded","false"),this.menu.setAttribute("aria-hidden","true"),this.menuItems[0].setAttribute("tabIndex","-1"),this.button.focus(),SNSW.Keyboard&&SNSW.Keyboard.detachPopup("DropMenu".concat(this.index))}),t(this,"buttonClickHandler",t=>{t.stopPropagation(),"false"!==this.button.getAttribute("aria-expanded")?this.closeMenu():this.openMenu()}),t(this,"buttonKeyDownHandler",t=>{switch(t.key){case"Enter":case" ":case"ArrowDown":t.preventDefault(),t.stopPropagation(),this.openMenu();break;case"ArrowUp":t.preventDefault(),t.stopPropagation(),this.openMenu(this.menuItems.length-1)}}),t(this,"menuItemClickHandler",t=>{t.stopPropagation(),this.setActiveMenuItem(t.currentTarget),this.closeMenu()}),t(this,"menuItemKeyDownHandler",t=>{switch(t.key){case"Enter":case" ":t.preventDefault(),t.currentTarget.click(),this.button.focus()}}),this.element=e,this.element&&this.element.nodeType&&(this.index=n,void 0===this.index&&(this.index=0),this.menu=this.element.querySelector("ul"),this.menu.setAttribute("id","menuButton".concat(this.index)),this.menu.setAttribute("role","menu"),this.menu.setAttribute("aria-hidden","true"),this.listItems=this.element.querySelectorAll("li"),this.listItems.forEach(t=>{t.setAttribute("role","none")}),this.menuItems=this.element.querySelectorAll("a"),this.menuItems.forEach((t,e)=>{t.setAttribute("role","menuitem"),t.setAttribute("tabIndex","-1"),0===e&&(t.setAttribute("aria-current","true"),this.listItems[e].classList.add("is-active")),t.addEventListener("click",this.menuItemClickHandler),t.addEventListener("keydown",this.menuItemKeyDownHandler)}),this.button=document.createElement("button"),this.button.setAttribute("aria-haspopup","true"),this.button.setAttribute("aria-controls",this.menu.getAttribute("id")),this.button.setAttribute("aria-expanded","false"),this.button.setAttribute("aria-label","Open ".concat(this.menu.getAttribute("aria-label"))),this.button.classList.add("reset--button"),this.element.insertBefore(this.button,this.menu),this.button.addEventListener("click",this.buttonClickHandler),this.button.addEventListener("keydown",this.buttonKeyDownHandler),SNSW.Keyboard&&(this.menu.addEventListener("focusin",()=>{SNSW.Keyboard.attachMenu(this,this.menuItems)}),this.menu.addEventListener("focusout",()=>{SNSW.Keyboard.detachMenu()})))}setActiveMenuItem(t){this.menuItems.forEach((e,n)=>{e!==t?(e.setAttribute("aria-current",""),this.listItems[n].classList.remove("is-active")):(e.setAttribute("aria-current","true"),this.listItems[n].classList.add("is-active"))})}openMenu(t){t=void 0!==t?t:0,this.button.setAttribute("aria-expanded","true"),this.menu.setAttribute("aria-hidden","false"),this.menuItems[0].setAttribute("tabIndex","0"),this.menuItems[t].focus(),SNSW.Keyboard&&SNSW.Keyboard.attachPopup("DropMenu".concat(this.index),this.closeMenu)}},window.addEventListener("DOMContentLoaded",()=>{const t=document.querySelectorAll(".drop-button:not(.is-excluded)");t&&t.forEach((t,e)=>{new SNSW.DropMenu(t,e)})})}(); | ||
!function(){"use strict";function t(t,e,i){return e in t?Object.defineProperty(t,e,{value:i,enumerable:!0,configurable:!0,writable:!0}):t[e]=i,t}function e(t,e,i){return e in t?Object.defineProperty(t,e,{value:i,enumerable:!0,configurable:!0,writable:!0}):t[e]=i,t}class i{constructor(){e(this,"attachDialog",(t,e,i,s)=>{SNSW.Dialogs.push({id:t,closefn:e,lastElement:s,firstElement:i})}),e(this,"detachDialog",t=>{SNSW.Dialogs=SNSW.Dialogs.filter(e=>e.id!==t)}),this.attachPopup=this.attachPopup.bind(this),this.detachPopup=this.detachPopup.bind(this),this.attachDialog=this.attachDialog.bind(this),this.detachDialog=this.detachDialog.bind(this),this.attachMenu=this.attachMenu.bind(this),this.detachMenu=this.detachMenu.bind(this),this.moveFocus=this.moveFocus.bind(this),this.handleGlobalKeydown=this.handleGlobalKeydown.bind(this),this.attachEventListeners=this.attachEventListeners.bind(this),this.detachEventListensers=this.detachEventListensers.bind(this),window.SNSW=window.SNSW||{},SNSW.Popups=SNSW.Popups||[],SNSW.Dialogs=SNSW.Dialogs||[],SNSW.Menu=null}attachPopup(t,e){SNSW.Popups.push({id:t,closefn:e})}detachPopup(t){SNSW.Popups=SNSW.Popups.filter(e=>e.id!==t)}attachMenu(t,e){SNSW.Menu={context:t,items:e}}detachMenu(){SNSW.Menu=null}getNextFocusableMenuItem(t){return arguments.length>1&&void 0!==arguments[1]&&arguments[1]?0===t?SNSW.Menu.items.length-1:t-1:SNSW.Menu.items.length>t+1?t+1:0}moveFocus(t){let e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];const{items:i}=SNSW.Menu,s=[...i].findIndex(e=>e===t);let n=this.getNextFocusableMenuItem(s,e),a=i[n].getAttribute("tabindex");if("-1"!==a)i[n].focus();else{for(;"-1"===a;)n=this.getNextFocusableMenuItem(n,e),a=i[n].getAttribute("tabindex");i[n].focus()}SNSW.Menu.active=n}handleGlobalClick(){const t=SNSW.Popups[SNSW.Popups.length-1],e=SNSW.Dialogs[SNSW.Dialogs.length-1];t&&t.closefn(),e&&e.closefn()}handleGlobalKeydown(t){const{key:e,target:i}=t,s=SNSW.Popups[SNSW.Popups.length-1],n=SNSW.Dialogs[SNSW.Dialogs.length-1];switch(e){case"Escape":s?s.closefn():n&&n.closefn();break;case"Tab":n&&(document.activeElement!==n.lastElement||t.getModifierState("Shift")?document.activeElement===n.firstElement&&t.getModifierState("Shift")&&(t.preventDefault(),n.lastElement.focus()):(t.preventDefault(),n.firstElement.focus()));break;case"ArrowDown":case"ArrowRight":SNSW.Menu&&(t.preventDefault(),this.moveFocus(i));break;case"ArrowUp":case"ArrowLeft":SNSW.Menu&&(t.preventDefault(),this.moveFocus(i,!0))}}attachEventListeners(){SNSW.Popups&&SNSW.Menu&&SNSW.Dialogs||(window.addEventListener("click",this.handleGlobalClick),window.addEventListener("keydown",this.handleGlobalKeydown))}detachEventListensers(){window.removeEventListener("click",this.handleGlobalClick),window.removeEventListener("keydown",this.handleGlobalKeydown)}}class s{constructor(e,s){t(this,"keyboard",new i),t(this,"closeMenu",()=>{this.button.setAttribute("aria-expanded","false"),this.menu.setAttribute("aria-hidden","true"),this.menuItems.forEach(t=>t.setAttribute("tabIndex","-1")),this.button.setAttribute("tabIndex","0"),this.button.focus(),this.keyboard&&this.keyboard.detachPopup("DropMenu".concat(this.index))}),t(this,"buttonClickHandler",t=>{t.stopPropagation(),"false"!==this.button.getAttribute("aria-expanded")?this.closeMenu():this.openMenu()}),t(this,"buttonKeyDownHandler",t=>{switch(t.key){case"Enter":case" ":case"ArrowDown":t.preventDefault(),t.stopPropagation(),this.openMenu();break;case"ArrowUp":t.preventDefault(),t.stopPropagation(),this.openMenu(this.menuItems.length-1)}}),t(this,"menuItemClickHandler",t=>{t.stopPropagation(),this.setActiveMenuItem(t.currentTarget),this.closeMenu()}),t(this,"menuItemKeyDownHandler",t=>{switch(t.key){case"Enter":case" ":t.preventDefault(),t.currentTarget.click(),this.button.focus()}}),this.element=e,this.element&&this.element.nodeType&&(this.index=s,void 0===this.index&&(this.index=0),this.menu=this.element.querySelector("ul"),this.menu.setAttribute("id","menuButton".concat(this.index)),this.menu.setAttribute("role","menu"),this.menu.setAttribute("aria-hidden","true"),this.listItems=this.element.querySelectorAll("li"),this.listItems.forEach(t=>{t.setAttribute("role","none")}),this.menuItems=this.element.querySelectorAll("a"),this.menuItems.forEach((t,e)=>{t.setAttribute("role","menuitem"),t.setAttribute("tabIndex","-1"),0===e&&(t.setAttribute("aria-current","true"),this.listItems[e].classList.add("is-active")),t.addEventListener("click",this.menuItemClickHandler),t.addEventListener("keydown",this.menuItemKeyDownHandler)}),this.button=document.createElement("button"),this.button.setAttribute("aria-haspopup","true"),this.button.setAttribute("aria-controls",this.menu.getAttribute("id")),this.button.setAttribute("aria-expanded","false"),this.button.setAttribute("aria-label","Open ".concat(this.menu.getAttribute("aria-label"))),this.button.classList.add("reset--button"),this.element.insertBefore(this.button,this.menu),this.button.addEventListener("click",this.buttonClickHandler),this.button.addEventListener("keydown",this.buttonKeyDownHandler),this.keyboard&&(this.menu.addEventListener("focusin",()=>{this.keyboard.attachMenu(this,this.menuItems)}),this.menu.addEventListener("focusout",()=>{this.keyboard.detachMenu()}),this.keyboard.attachEventListeners()))}setActiveMenuItem(t){this.menuItems.forEach((e,i)=>{e!==t?(e.setAttribute("aria-current",""),this.listItems[i].classList.remove("is-active")):(e.setAttribute("aria-current","true"),this.listItems[i].classList.add("is-active"))})}openMenu(t){t=void 0!==t?t:0,this.button.setAttribute("aria-expanded","true"),this.menu.setAttribute("aria-hidden","false"),this.menuItems.forEach(t=>t.setAttribute("tabIndex","0")),this.menuItems[t].focus(),this.keyboard&&this.keyboard.attachPopup("DropMenu".concat(this.index),this.closeMenu)}}window.SNSW=window.SNSW||{},SNSW.DropMenu=s,window.addEventListener("DOMContentLoaded",()=>{const t=document.querySelectorAll(".drop-button:not(.is-excluded)");t&&t.forEach((t,e)=>{new s(t,e)})})}(); |
{ | ||
"name": "@servicensw/drop-menu", | ||
"version": "2.3.8", | ||
"version": "2.4.0", | ||
"description": "Drop menu component", | ||
@@ -12,3 +12,11 @@ "repository": { | ||
"license": "MIT", | ||
"main": "dist/drop-menu.js", | ||
"main": "dist/cjs/index.js", | ||
"module": "dist/esm/index.js", | ||
"exports": { | ||
"./css": "./dist/drop-menu.css", | ||
".": { | ||
"import": "./dist/esm/index.js", | ||
"require": "./dist/cjs/index.js" | ||
} | ||
}, | ||
"style": "src/drop-menu.css", | ||
@@ -28,3 +36,3 @@ "files": [ | ||
"build:css": "NODE_ENV=production postcss src/drop-menu.css --dir dist --config ../../postcss.config.js", | ||
"build:js": "NODE_ENV=production rollup src/drop-menu.es6.js --o dist/drop-menu.js --f iife --name SNSW.DropMenu --config ../../rollup.config.js --silent", | ||
"build:js": "NODE_ENV=production rollup src/drop-menu.es6.js --o dist/drop-menu.js --f iife --name SNSW.DropMenu --config ../../rollup.config.js --silent && NODE_ENV=production rollup src/index.js --format cjs --o dist/cjs/index.js --config ../../rollup.config.js --silent && NODE_ENV=production rollup src/index.js --o dist/esm/index.js --config ../../rollup.config.js --silent", | ||
"clean": "rm -rf ./dist", | ||
@@ -40,3 +48,3 @@ "prepare": "npm run clean && npm run build:css && npm run build:js" | ||
"dependencies": { | ||
"@servicensw/base": "^2.10.1", | ||
"@servicensw/base": "^2.11.0", | ||
"@servicensw/constants": "^2.0.11" | ||
@@ -54,3 +62,3 @@ }, | ||
], | ||
"gitHead": "bf2086418aca4bd3d199a015f03b1e89cabf613a" | ||
"gitHead": "d9ed8d8209536c25d5345a3d8e5b21319230333f" | ||
} |
@@ -33,4 +33,8 @@ # @servicensw/drop-menu | ||
```js | ||
const menuElement = document.querySelector(".drop-button") | ||
const dropMenu = new SNSW.DropMenu(menuElement) | ||
import DropMenu from "@servicensw/drop-menu" | ||
const dropMenus = document.querySelectorAll(".drop-button:not(.is-excluded)") | ||
dropMenus.forEach((element, index) => { | ||
new DropMenu(element, index) | ||
}) | ||
``` | ||
@@ -37,0 +41,0 @@ |
/** | ||
* @file Native ES6 component to provide a drop menu. | ||
* @see Aria reference at: https://www.w3.org/TR/wai-aria-practices-1.1/examples/menu-button/menu-button-links.html | ||
* @file Initialise DropMenu. | ||
*/ | ||
import { keyboard, polyfill } from "@servicensw/base/src/errors" | ||
import DropMenu from "./DropMenu" | ||
window.SNSW = window.SNSW || {} | ||
SNSW.DropMenu = DropMenu | ||
/** | ||
* Error handling. | ||
* | ||
* Warnings are shown before any errors are thrown so the complete set of issues | ||
* is known immediately. | ||
*/ | ||
if (typeof SNSW.Keyboard === "undefined") { | ||
console.warn(keyboard("Drop menu")) // eslint-disable-line no-console | ||
} | ||
if (!NodeList.prototype.forEach) { | ||
throw new Error(polyfill("Drop menu")) | ||
} | ||
SNSW.DropMenu = class DropMenu { | ||
/** | ||
* Initialise the component | ||
* @param {HTMLElement} element - The drop menu element. | ||
* @param {number} [index] - The index number of the element. | ||
*/ | ||
constructor(element, index) { | ||
this.element = element | ||
if (!this.element || !this.element.nodeType) { | ||
return | ||
} | ||
this.index = index | ||
if (typeof this.index === "undefined") { | ||
this.index = 0 | ||
} | ||
// Setup the menu element. | ||
this.menu = this.element.querySelector("ul") | ||
this.menu.setAttribute("id", `menuButton${this.index}`) | ||
this.menu.setAttribute("role", "menu") | ||
this.menu.setAttribute("aria-hidden", "true") | ||
// Setup the list items. | ||
this.listItems = this.element.querySelectorAll("li") | ||
this.listItems.forEach(el => { | ||
// Setting role="none" hides implied listitem role for assistive technologies. | ||
// @see https://www.w3.org/TR/wai-aria-practices-1.1/#presentation_role | ||
el.setAttribute("role", "none") | ||
}) | ||
// Setup the menu items. | ||
this.menuItems = this.element.querySelectorAll("a") | ||
this.menuItems.forEach((el, i) => { | ||
el.setAttribute("role", "menuitem") | ||
// Remove the a elements from normal focus flow. | ||
el.setAttribute("tabIndex", "-1") | ||
// Make this first item active by default. | ||
if (i === 0) { | ||
el.setAttribute("aria-current", "true") | ||
this.listItems[i].classList.add("is-active") | ||
} | ||
// Add handlers. | ||
el.addEventListener("click", this.menuItemClickHandler) | ||
el.addEventListener("keydown", this.menuItemKeyDownHandler) | ||
}) | ||
// Create the button element. | ||
this.button = document.createElement("button") | ||
this.button.setAttribute("aria-haspopup", "true") | ||
this.button.setAttribute("aria-controls", this.menu.getAttribute("id")) | ||
this.button.setAttribute("aria-expanded", "false") | ||
this.button.setAttribute( | ||
"aria-label", | ||
`Open ${this.menu.getAttribute("aria-label")}` | ||
) | ||
this.button.classList.add("reset--button") | ||
this.element.insertBefore(this.button, this.menu) | ||
// Add handlers. | ||
this.button.addEventListener("click", this.buttonClickHandler) | ||
this.button.addEventListener("keydown", this.buttonKeyDownHandler) | ||
// Add focus handler for menu links. | ||
if (SNSW.Keyboard) { | ||
this.menu.addEventListener("focusin", () => { | ||
SNSW.Keyboard.attachMenu(this, this.menuItems) | ||
}) | ||
this.menu.addEventListener("focusout", () => { | ||
SNSW.Keyboard.detachMenu() | ||
}) | ||
} | ||
} | ||
setActiveMenuItem(menuItem) { | ||
this.menuItems.forEach((element, index) => { | ||
if (element !== menuItem) { | ||
element.setAttribute("aria-current", "") | ||
this.listItems[index].classList.remove("is-active") | ||
} else { | ||
element.setAttribute("aria-current", "true") | ||
this.listItems[index].classList.add("is-active") | ||
} | ||
}) | ||
} | ||
openMenu(focus) { | ||
focus = typeof focus !== "undefined" ? focus : 0 | ||
this.button.setAttribute("aria-expanded", "true") | ||
this.menu.setAttribute("aria-hidden", "false") | ||
this.menuItems[0].setAttribute("tabIndex", "0") | ||
this.menuItems[focus].focus() | ||
// Attach global events. | ||
if (SNSW.Keyboard) { | ||
SNSW.Keyboard.attachPopup(`DropMenu${this.index}`, this.closeMenu) | ||
} | ||
} | ||
closeMenu = () => { | ||
this.button.setAttribute("aria-expanded", "false") | ||
this.menu.setAttribute("aria-hidden", "true") | ||
this.menuItems[0].setAttribute("tabIndex", "-1") | ||
this.button.focus() | ||
// Detach global event. | ||
if (SNSW.Keyboard) { | ||
SNSW.Keyboard.detachPopup(`DropMenu${this.index}`) | ||
} | ||
} | ||
buttonClickHandler = event => { | ||
event.stopPropagation() | ||
if (this.button.getAttribute("aria-expanded") === "false") { | ||
this.openMenu() | ||
return | ||
} | ||
this.closeMenu() | ||
} | ||
buttonKeyDownHandler = event => { | ||
switch (event.key) { | ||
case "Enter": | ||
case " ": | ||
case "ArrowDown": | ||
event.preventDefault() | ||
event.stopPropagation() | ||
this.openMenu() | ||
break | ||
case "ArrowUp": | ||
event.preventDefault() | ||
event.stopPropagation() | ||
this.openMenu(this.menuItems.length - 1) | ||
break | ||
default: | ||
break | ||
} | ||
} | ||
menuItemClickHandler = event => { | ||
event.stopPropagation() | ||
this.setActiveMenuItem(event.currentTarget) | ||
this.closeMenu() | ||
} | ||
menuItemKeyDownHandler = event => { | ||
switch (event.key) { | ||
case "Enter": | ||
case " ": | ||
event.preventDefault() | ||
event.currentTarget.click() | ||
this.button.focus() | ||
break | ||
default: | ||
break | ||
} | ||
} | ||
} | ||
/** | ||
* Standard initialise for all .drop-buttom elements. | ||
@@ -188,5 +17,5 @@ */ | ||
dropMenus.forEach((element, index) => { | ||
;(() => new SNSW.DropMenu(element, index))() | ||
new DropMenu(element, index) | ||
}) | ||
} | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
33494
12
411
56
1
Updated@servicensw/base@^2.11.0