picocss/docs/js/modal.js
2024-01-27 13:53:19 +07:00

101 lines
2.7 KiB
JavaScript

/*
* Modal
*
* Pico.css - https://picocss.com
* Copyright 2019-2023 - Licensed under MIT
*/
// Config
const isOpenClass = "modal-is-open"
const openingClass = "modal-is-opening"
const closingClass = "modal-is-closing"
const animationDuration = 400 // ms
let visibleModal = null
// Toggle modal
const toggleModal = event => {
event.preventDefault()
const modal = document.getElementById(
event.currentTarget.getAttribute("data-target")
)
typeof modal != "undefined" && modal != null && isModalOpen(modal)
? closeModal(modal)
: openModal(modal)
}
// Is modal open
const isModalOpen = modal => {
return modal.hasAttribute("open") && modal.getAttribute("open") != "false"
? true
: false
}
// Open modal
const openModal = modal => {
if (isScrollbarVisible()) {
document.documentElement.style.setProperty(
"--scrollbar-width",
`${getScrollbarWidth()}px`
)
}
document.documentElement.classList.add(isOpenClass, openingClass)
setTimeout(() => {
visibleModal = modal
document.documentElement.classList.remove(openingClass)
}, animationDuration)
modal.setAttribute("open", true)
}
// Close modal
const closeModal = modal => {
visibleModal = null
document.documentElement.classList.add(closingClass)
setTimeout(() => {
document.documentElement.classList.remove(closingClass, isOpenClass)
document.documentElement.style.removeProperty("--scrollbar-width")
modal.removeAttribute("open")
}, animationDuration)
}
// Close with a click outside
document.addEventListener("click", event => {
if (visibleModal != null) {
const modalContent = visibleModal.querySelector("article")
const isClickInside = modalContent.contains(event.target)
!isClickInside && closeModal(visibleModal)
}
})
// Close with Esc key
document.addEventListener("keydown", event => {
if (event.key === "Escape" && visibleModal != null) {
closeModal(visibleModal)
}
})
// Get scrollbar width
const getScrollbarWidth = () => {
// Creating invisible container
const outer = document.createElement("div")
outer.style.visibility = "hidden"
outer.style.overflow = "scroll" // forcing scrollbar to appear
outer.style.msOverflowStyle = "scrollbar" // needed for WinJS apps
document.body.appendChild(outer)
// Creating inner element and placing it in the container
const inner = document.createElement("div")
outer.appendChild(inner)
// Calculating difference between container's full width and the child width
const scrollbarWidth = outer.offsetWidth - inner.offsetWidth
// Removing temporary elements from the DOM
outer.parentNode.removeChild(outer)
return scrollbarWidth
}
// Is scrollbar visible
const isScrollbarVisible = () => {
return document.body.scrollHeight > screen.height
}