mirror of
https://github.com/picocss/pico.git
synced 2025-04-20 08:45:06 -04:00
101 lines
2.7 KiB
JavaScript
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
|
|
}
|