@randstad-design/orbit-multitheme
Version:
multitheme Front-end code based on Randstad Human Forward components
182 lines (159 loc) • 4.29 kB
JavaScript
/**
* popover.js
*/
import ElementHelpers from '../helpers/element-helpers';
import trapFocus from '../helpers/trapFocus';
/**
* Declare constants
*/
const attributeBase = 'data-rs-popover';
export class Popover {
constructor(element) {
this.element = element;
this.trigger = ElementHelpers.getElementByAttribute(
this.attributes.trigger,
this.element.getAttribute(attributeBase)
);
this.overlay = ElementHelpers.getElementByAttribute(
this.attributes.overlay
);
this.disableOverlay = this.element.hasAttribute(
this.attributes.disableOverlay
);
this.popoverOpen;
this.addEventHandlers();
this.isOpenByDefault();
this.keystroke = 0;
}
/**
* Declare classes
*/
get classes() {
return {
popoverActive: 'popover--active',
modalOverlayActive: 'modal__overlay--active',
active: 'active'
};
}
/**
* Declare attribute constants
*/
get attributes() {
return {
overlay: `${attributeBase}-overlay`,
trigger: `${attributeBase}-trigger`,
disableOverlay: `${attributeBase}-disable-overlay`,
hidden: 'aria-hidden'
};
}
/**
* Add event handlers
*/
addEventHandlers() {
if (this.trigger) {
this.trigger.addEventListener('click', () => {
if (!this.popoverOpen) {
this.openPopover(this.element);
} else {
this.closePopover(this.popoverOpen);
}
this.toggleActiveClassOnTrigger();
});
}
if (this.overlay && !this.disableOverlay && this.popoverOpen) {
this.overlay.addEventListener('click', () => {
this.closePopover(this.popoverOpen);
if (this.trigger) {
this.toggleActiveClassOnTrigger();
}
});
} else {
window.addEventListener('click', (clickEvent) => {
if (!this.popoverOpen) {
return;
}
if (
(this.trigger && this.trigger.contains(clickEvent.target)) ||
this.popoverOpen.contains(clickEvent.target)
) {
return;
}
this.closePopover(this.popoverOpen);
if (this.trigger) {
this.toggleActiveClassOnTrigger();
}
});
}
document.addEventListener('keydown', (keydownEvent) => {
this.handleButtonKeys(keydownEvent);
});
}
isOpenByDefault() {
return this.element.classList.contains(this.classes.popoverActive)
? (this.popoverOpen = this.element)
: null;
}
openPopover(activePopover) {
if (!activePopover) {
return;
}
activePopover.classList.add(this.classes.popoverActive);
activePopover.removeAttribute(this.attributes.hidden);
if (this.overlay !== null && !this.disableOverlay) {
this.overlay.classList.add(this.classes.modalOverlayActive);
}
this.popoverOpen = activePopover;
}
closePopover(activePopover) {
if (!activePopover) {
return;
}
activePopover.classList.remove(this.classes.popoverActive);
activePopover.setAttribute(this.attributes.hidden, 'true');
if (this.overlay && !this.disableOverlay) {
this.overlay.classList.remove(this.classes.modalOverlayActive);
}
this.popoverOpen = false;
this.keystroke = 0;
}
/**
* Toggle active class on trigger element
*/
toggleActiveClassOnTrigger() {
if (this.trigger.classList.contains(this.classes.active)) {
this.trigger.classList.remove(this.classes.active);
} else {
this.trigger.classList.add(this.classes.active);
}
}
/**
* Handle button keys - handle key presses escape
*
* @param {Event} event - event triggered
*/
handleButtonKeys(event) {
if (event != null) {
switch (ElementHelpers.getKeyCodeOnKeyDownEvent(event)) {
case 'Tab':
trapFocus(event, this.element, this.popoverOpen, this.keystroke);
if (this.popoverOpen) {
this.keystroke++;
}
break;
case 'Escape':
if (this.popoverOpen) {
this.closePopover(this.popoverOpen);
if (this.trigger) {
this.trigger.focus();
}
}
}
}
}
/**
* Get selector
*/
static getSelector() {
return `[${attributeBase}]`;
}
}