Newer
Older
gnexus-ui-kit / src / js / components / overlays.js
@root root 7 hours ago 2 KB Tech
const initializedRoots = new WeakSet();
let keyboardDismissInitialized = false;

function closeNode(node) {
	node.classList.remove("is-open");
	node.querySelectorAll("[aria-expanded='true']").forEach(trigger => {
		trigger.setAttribute("aria-expanded", "false");
	});
}

function closeAll(except = null) {
	document.querySelectorAll(".dropdown.is-open, .popover.is-open, .tooltip.is-open").forEach(node => {
		if(node !== except) {
			closeNode(node);
		}
	});
}

function initTabs(root = document) {
	root.addEventListener("click", event => {
		const tab = event.target.closest(".tab");

		if(!tab) {
			return;
		}

		const tabs = tab.closest(".tabs");

		if(!tabs) {
			return;
		}

		tabs.querySelectorAll(".tab").forEach(item => {
			const isActive = item === tab;
			item.classList.toggle("tab-active", isActive);
			item.setAttribute("aria-selected", String(isActive));
		});
	});
}

function initDropdowns(root = document) {
	root.addEventListener("click", event => {
		const trigger = event.target.closest("[data-dropdown-toggle]");

		if(!trigger) {
			return;
		}

		const dropdown = trigger.closest(".dropdown");

		if(!dropdown) {
			return;
		}

		event.preventDefault();
		const isOpen = dropdown.classList.contains("is-open");
		closeAll(dropdown);
		dropdown.classList.toggle("is-open", !isOpen);
		trigger.setAttribute("aria-expanded", String(!isOpen));
	});
}

function initPopovers(root = document) {
	root.addEventListener("click", event => {
		const trigger = event.target.closest("[data-popover-toggle]");

		if(!trigger) {
			return;
		}

		const popover = trigger.closest(".popover");

		if(!popover) {
			return;
		}

		event.preventDefault();
		const isOpen = popover.classList.contains("is-open");
		closeAll(popover);
		popover.classList.toggle("is-open", !isOpen);
		trigger.setAttribute("aria-expanded", String(!isOpen));
	});
}

function initTooltips(root = document) {
	root.addEventListener("click", event => {
		const trigger = event.target.closest("[data-tooltip-toggle]");

		if(!trigger) {
			return;
		}

		const tooltip = trigger.closest(".tooltip");

		if(!tooltip) {
			return;
		}

		event.preventDefault();
		const isOpen = tooltip.classList.contains("is-open");
		closeAll(tooltip);
		tooltip.classList.toggle("is-open", !isOpen);
	});
}

function initDismiss(root = document) {
	root.addEventListener("click", event => {
		if(event.target.closest(".dropdown, .popover, .tooltip")) {
			return;
		}

		closeAll();
	});

	if(!keyboardDismissInitialized) {
		document.addEventListener("keydown", event => {
			if(event.key === "Escape") {
				closeAll();
			}
		});

		keyboardDismissInitialized = true;
	}
}

function init(root = document) {
	if(initializedRoots.has(root)) {
		return;
	}

	initTabs(root);
	initDropdowns(root);
	initPopovers(root);
	initTooltips(root);
	initDismiss(root);
	initializedRoots.add(root);
}

export default {
	init,
	closeAll
};