import { bodyFreeze } from './bodyFreeze' export type ModalInstance = { open: (freeze?: boolean) => void close: () => void replaceWith: (modal: ModalInstance) => void remove: () => void } 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): ModalInstance | undefined => { const { trigger, modal, onOpen, onClose } = (typeof config === 'string' ? {} : config) as Modal const modalSelector = typeof config === 'string' ? config : modal const triggerDOM = trigger ? document.querySelector(trigger) : null const modalDOM = document.querySelector(modalSelector) if (modalDOM instanceof HTMLElement) { const closeOptions = modalDOM.dataset.close?.split(',') const handleOpen = (_e?: Event, freeze = true) => { modalDOM.dataset.show = 'true' if (freeze) { bodyFreeze() } onOpen?.({ trigger: triggerDOM, modal: modalDOM }) } const handleClose = (_e?: Event, unfreeze = true) => { modalDOM.dataset.show = '' if (unfreeze) { bodyFreeze(false) } onClose?.({ trigger: triggerDOM, modal: modalDOM }) } const closeHandlers = { icon() { const close = modalDOM.querySelector('[data-id="close"]') return { add: () => close?.addEventListener('click', handleClose), remove: () => close?.removeEventListener('click', handleClose) } }, esc() { const listener = (event: KeyboardEvent) => { if (modalDOM.dataset.show && event.key === 'Escape') { handleClose() } } return { add: () => document.addEventListener('keydown', listener), remove: () => document.removeEventListener('keydown', listener) } }, overlay() { const close = modalDOM.nextElementSibling return { add: () => close?.addEventListener('click', handleClose), remove: () => close?.removeEventListener('click', handleClose) } } } triggerDOM?.addEventListener('click', handleOpen) closeOptions?.forEach(option => { closeHandlers[option as keyof typeof closeHandlers]().add() }) return { open(freeze?: boolean) { handleOpen(undefined, freeze) }, close() { handleClose() }, replaceWith(modal: ModalInstance) { modal.open(false) handleClose(undefined, false) }, remove() { triggerDOM?.removeEventListener('click', handleOpen) closeOptions?.forEach(option => { closeHandlers[option as keyof typeof closeHandlers]().remove() }) } } } } export const closeModal = (modal: string) => { const modalDOM = document.querySelector(modal) if (modalDOM instanceof HTMLElement) { modalDOM.dataset.show = '' bodyFreeze(false) } }