webcoreui
Version:
UI component and template library for Astro, Svelte, and React apps styled with Sass.
135 lines (103 loc) • 3.75 kB
text/typescript
import { bodyFreeze } from './bodyFreeze'
export type ModalCallback = {
trigger: Element | null
modal: HTMLElement
}
export type Modal = {
trigger: string
modal: string
onOpen?: (args: ModalCallback) => unknown
onClose?: (args: ModalCallback) => unknown
}
export const modal = (config: Modal | string) => {
const {
trigger,
modal,
onOpen,
onClose
} = (typeof config === 'string' ? {} : config) as Modal
const modalSelector = typeof config === 'string' ? config : modal
const triggerDOM = document.querySelector(trigger)
const modalDOM = document.querySelector(modalSelector) as HTMLElement
if (modalDOM) {
const closeOptions = modalDOM.dataset.close?.split(',')
const handleClose = {
icon() {
const close = modalDOM.querySelector('[data-id="close"]')
const listener = () => {
modalDOM.dataset.show = ''
bodyFreeze(false)
onClose?.({
trigger: triggerDOM,
modal: modalDOM
})
}
return {
add: () => close?.addEventListener('click', listener),
remove: () => close?.removeEventListener('click', listener)
}
},
esc() {
const listener = (event: KeyboardEvent) => {
if (modalDOM.dataset.show && event.key === 'Escape') {
modalDOM.dataset.show = ''
bodyFreeze(false)
onClose?.({
trigger: triggerDOM,
modal: modalDOM
})
}
}
return {
add: () => document.addEventListener('keydown', listener),
remove: () => document.removeEventListener('keydown', listener)
}
},
overlay() {
const close = modalDOM.nextElementSibling
const listener = () => {
modalDOM.dataset.show = ''
bodyFreeze(false)
onClose?.({
trigger: triggerDOM,
modal: modalDOM
})
}
return {
add: () => close?.addEventListener('click', listener),
remove: () => close?.removeEventListener('click', listener)
}
}
}
const handleOpen = () => {
modalDOM.dataset.show = 'true'
bodyFreeze()
onOpen?.({
trigger: triggerDOM,
modal: modalDOM
})
}
triggerDOM?.addEventListener('click', handleOpen)
closeOptions?.forEach(option => {
handleClose[option as keyof typeof handleClose]().add()
})
return {
open() {
handleOpen()
},
remove() {
triggerDOM?.removeEventListener('click', handleOpen)
closeOptions?.forEach(option => {
handleClose[option as keyof typeof handleClose]().remove()
})
}
}
}
}
export const closeModal = (modal: string) => {
const modalDOM = document.querySelector(modal) as HTMLElement
if (modalDOM) {
modalDOM.dataset.show = ''
bodyFreeze(false)
}
}