// Adapted from https://github.com/excid3/tailwindcss-stimulus-components/blob/master/src/modal.js
// Designed to work with tailwindcss
//
// Visit The Stimulus Handbook for more details
// https://stimulusjs.org/handbook/introduction
//
// This example controller works with specially annotated HTML like:
//
//
import { Controller } from "stimulus"
export default class extends Controller {
static targets = ["container"];
connect() {
// The class we should toggle on the container
this.toggleClass = this.data.get("class") || "hidden"
// The HTML for the background element
this.backgroundHtml = this.data.get("backgroundHtml") || this._backgroundHTML()
// The ID of the background to hide/remove
this.backgroundId = this.data.get("backgroundId") || "modal-background"
// Let the user close the modal by clicking on the background
this.allowBackgroundClose = (this.data.get("allowBackgroundClose") || "true") === "true"
}
disconnect() {
this.close()
}
open(e) {
e.preventDefault()
e.target.blur()
// Lock the scroll and save current scroll position
this.lockScroll()
// Unhide the modal
this.containerTarget.classList.remove(this.toggleClass)
// Insert the background
if (!this.data.get("disable-backdrop")) {
document.body.insertAdjacentHTML("beforeend", this.backgroundHtml)
this.background = document.querySelector(`#${this.backgroundId}`)
}
}
close(e) {
if (e) e.preventDefault()
// Unlock the scroll and restore previous scroll position
this.unlockScroll()
// Hide the modal
this.containerTarget.classList.add(this.toggleClass)
// Remove the background
if (this.background) { this.background.remove() }
}
closeBackground(e) {
if (this.allowBackgroundClose && e.target === this.containerTarget) {
this.close(e)
}
}
closeWithKeyboard(e) {
if (e.keyCode === 27 && !this.containerTarget.classList.contains(this.toggleClass)) {
this.close(e)
}
}
_backgroundHTML() {
return ""
}
lockScroll() {
// Add right padding to the body so the page doesn't shift
// when we disable scrolling
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth
document.body.style.paddingRight = `${scrollbarWidth}px`
// Save the scroll position
this.saveScrollPosition()
// Add classes to body to fix its position
document.body.classList.add("fixed", "inset-x-0", "overflow-hidden")
// Add negative top position in order for body to stay in place
document.body.style.top = `-${this.scrollPosition}px`
}
unlockScroll() {
// Remove tweaks for scrollbar
document.body.style.paddingRight = null
// Remove classes from body to unfix position
document.body.classList.remove("fixed", "inset-x-0", "overflow-hidden")
// Restore the scroll position of the body before it got locked
this.restoreScrollPosition()
// Remove the negative top inline style from body
document.body.style.top = null
}
saveScrollPosition() {
this.scrollPosition = window.pageYOffset || document.body.scrollTop
}
restoreScrollPosition() {
document.documentElement.scrollTop = this.scrollPosition
}
}