pure-modal
Version:
A lightweight, accessible, vanilla JavaScript modal component
6 lines • 5.36 kB
JavaScript
/**
* Pure Modal v1.0.3
* (c) 2019 Roman Slonov
* Released under the MIT License.
*/
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var ClassName={BACKDROP:"modal-backdrop",OPEN:"is-open",IN:"in",OUT:"out",DIALOG:"modal-dialog"},KeyCodes={ESC:27,TAB:9},DefaultConfig={transition:!0},throwError=function(s){return window.console.error("PureModal: "+s)},reflow=function(s){return s.offsetHeight},PureModal=function s(t,e){this.id=t,this.config=Object.assign({},DefaultConfig,e),this.modal=s.findModal(this.id),this.dialog=this.modal.querySelector("."+ClassName.DIALOG),this.backdrop=null,this.isOpen=!1,this.isInit=!1,this.isTransitioning=!1,this.triggers=s.findTriggers(this.id),this.closeEls=null,this.focusableEls=null,this.focusedElBeforeOpen=null,this.firstFocusableEl=null,this.lastFocusableEl=null,this.open=this.open.bind(this),this.close=this.close.bind(this),this.onDismiss=this.onDismiss.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this)};PureModal.prototype.init=function(){var s=this;this.isInit?throwError("Event listeners already added."):(this.triggers.forEach(function(t){return t.addEventListener("click",s.open)}),this.isInit=!0)},PureModal.prototype.destroy=function(){var s=this;this.isInit?(this.triggers.forEach(function(t){return t.removeEventListener("click",s.open)}),this.isInit=!1):throwError("Event listeners already removed.")},PureModal.prototype.open=function(s){var t=this;this.isTransitioning||(s.preventDefault(),"function"==typeof this.config.beforeOpen&&this.config.beforeOpen(),this.focusedElBeforeOpen=document.activeElement,this.focusableEls=Array.from(this.dialog.querySelectorAll('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex="0"]')),this.firstFocusableEl=this.focusableEls[0],this.lastFocusableEl=this.focusableEls[this.focusableEls.length-1],this.showBackdrop(),this.modal.style.display="block",this.config.transition?(this.isTransitioning=!0,this.modal.classList.add(ClassName.OPEN),this.modal.classList.add(ClassName.IN),this.openWithTransition()):this.firstFocusableEl.focus(),document.addEventListener("mousedown",this.onDismiss),document.addEventListener("keydown",this.handleKeyDown),this.closeEls=Array.from(this.modal.querySelectorAll('[data-dismiss="modal"]')),this.closeEls.forEach(function(s){return s.addEventListener("click",t.close)}),this.isOpen=!0,"function"==typeof this.config.onOpen&&this.config.onOpen())},PureModal.prototype.openWithTransition=function(){var s=this,t=function(){s.dialog.removeEventListener("animationend",t),s.firstFocusableEl.focus(),"function"==typeof s.config.onOpen&&s.config.onOpen(),s.isTransitioning=!1};this.dialog.addEventListener("animationend",t)},PureModal.prototype.close=function(){var s=this;this.isTransitioning||("function"==typeof this.config.beforeClose&&this.config.beforeClose(),this.config.transition?(this.isTransitioning=!0,this.modal.classList.remove(ClassName.IN),this.modal.classList.remove(ClassName.OPEN),this.modal.classList.add(ClassName.OUT),this.closeWithTransition(),this.closeBackdrop()):(this.modal.style.display="none",this.modal.classList.remove(ClassName.OPEN),this.closeBackdrop(),"function"==typeof this.config.onClose&&this.config.onClose()),document.removeEventListener("mousedown",this.onDismiss),document.removeEventListener("keydown",this.handleKeyDown),this.closeEls.forEach(function(t){return t.removeEventListener("click",s.close)}),this.isOpen=!1,this.focusedElBeforeOpen.focus())},PureModal.prototype.closeWithTransition=function(){var s=this,t=function(){s.dialog.removeEventListener("animationend",t),s.modal.style.display="none",s.modal.classList.remove(ClassName.OUT),"function"==typeof s.config.onClose&&s.config.onClose(),s.isTransitioning=!1};this.dialog.addEventListener("animationend",t)},PureModal.prototype.onDismiss=function(s){!this.dialog.contains(s.target)&&this.isOpen&&this.close()},PureModal.prototype.showBackdrop=function(){this.backdrop=document.createElement("div"),this.backdrop.tabIndex=-1,this.backdrop.classList.add(ClassName.BACKDROP),this.config.transition&&this.backdrop.classList.add(ClassName.IN),document.body.appendChild(this.backdrop),reflow(this.backdrop),this.backdrop.classList.add(ClassName.OPEN)},PureModal.prototype.closeBackdrop=function(){this.config.transition?(this.backdrop.classList.remove(ClassName.IN),this.backdrop.classList.remove(ClassName.OPEN),this.backdrop.classList.add(ClassName.OUT),this.closeBackdropWithTransition()):this.backdrop.remove()},PureModal.prototype.closeBackdropWithTransition=function(){var s=this,t=function(){s.backdrop.removeEventListener("transitionend",t),s.backdrop.remove()};this.backdrop.addEventListener("transitionend",t)},PureModal.prototype.handleKeyDown=function(s){var t=this;switch(s.keyCode){case KeyCodes.TAB:if(1===this.focusableEls.length){s.preventDefault();break}s.shiftKey?document.activeElement===t.firstFocusableEl&&(s.preventDefault(),t.lastFocusableEl.focus()):document.activeElement===t.lastFocusableEl&&(s.preventDefault(),t.firstFocusableEl.focus());break;case KeyCodes.ESC:this.close()}},PureModal.findTriggers=function(s){return Array.from(document.querySelectorAll('[data-toggle="modal"][data-target="'+s+'"]'))},PureModal.findModal=function(s){return document.getElementById(s)},exports.default=PureModal;