class DetailsModal extends HTMLElement { constructor() { super(); this.detailsContainer = this.querySelector('details'); this.summaryToggle = this.querySelector('summary'); this.detailsContainer.addEventListener( 'keyup', (event) => event.code.toUpperCase() === 'ESCAPE' && this.close() ); this.summaryToggle.addEventListener( 'click', this.onSummaryClick.bind(this) ); this.querySelector('button[type="button"]').addEventListener( 'click', this.close.bind(this) ); this.summaryToggle.setAttribute('role', 'button'); } isOpen() { return this.detailsContainer.hasAttribute('open'); } onSummaryClick(event) { event.preventDefault(); event.target.closest('details').hasAttribute('open') ? this.close() : this.open(event); } onBodyClick(event) { if (!this.contains(event.target) || event.target.classList.contains('modal-overlay')) this.close(false); } open(event) { this.onBodyClickEvent = this.onBodyClickEvent || this.onBodyClick.bind(this); event.target.closest('details').setAttribute('open', true); document.body.addEventListener('click', this.onBodyClickEvent); document.body.classList.add('overflow-hidden'); trapFocus( this.detailsContainer.querySelector('[tabindex="-1"]'), this.detailsContainer.querySelector('input:not([type="hidden"])') ); } close(focusToggle = true) { removeTrapFocus(focusToggle ? this.summaryToggle : null); this.detailsContainer.removeAttribute('open'); document.body.removeEventListener('click', this.onBodyClickEvent); document.body.classList.remove('overflow-hidden'); } } customElements.define('details-modal', DetailsModal);