initial commit
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
if (!customElements.get('cart-disclosure-modal')) {
|
||||
class CartDisclosureModal extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.onOpenerClick = this.onOpenerClick.bind(this);
|
||||
this.onCloseClick = this.onCloseClick.bind(this);
|
||||
this.onModalClick = this.onModalClick.bind(this);
|
||||
this.onKeyUp = this.onKeyUp.bind(this);
|
||||
this.removeIfOpenerDisconnected = this.removeIfOpenerDisconnected.bind(this);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
if (this.initialized) return;
|
||||
|
||||
this.initialized = true;
|
||||
this.dialog = this.querySelector('[role="dialog"]');
|
||||
const controlsId = this.dialog?.id;
|
||||
this.opener = this.previousElementSibling?.classList.contains('cart-item__disclosure')
|
||||
? this.previousElementSibling
|
||||
: controlsId
|
||||
? document.querySelector(`[aria-controls="${controlsId}"]`)
|
||||
: null;
|
||||
this.closeButton = this.querySelector('[data-cart-disclosure-close]');
|
||||
|
||||
let shouldRestoreOpen = false;
|
||||
document.querySelectorAll('cart-disclosure-modal').forEach((modal) => {
|
||||
if (modal === this || modal.id !== this.id) return;
|
||||
|
||||
shouldRestoreOpen = shouldRestoreOpen || modal.hasAttribute('open');
|
||||
modal.remove();
|
||||
});
|
||||
|
||||
this.opener?.addEventListener('click', this.onOpenerClick);
|
||||
this.closeButton?.addEventListener('click', this.onCloseClick);
|
||||
this.addEventListener('click', this.onModalClick);
|
||||
this.addEventListener('keyup', this.onKeyUp);
|
||||
|
||||
if (this.parentElement !== document.body) {
|
||||
this.isMoving = true;
|
||||
document.body.appendChild(this);
|
||||
this.isMoving = false;
|
||||
}
|
||||
|
||||
this.observeOpener();
|
||||
|
||||
if (shouldRestoreOpen) this.show();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.isMoving) return;
|
||||
|
||||
this.openerObserver?.disconnect();
|
||||
this.opener?.removeEventListener('click', this.onOpenerClick);
|
||||
this.closeButton?.removeEventListener('click', this.onCloseClick);
|
||||
this.removeEventListener('click', this.onModalClick);
|
||||
this.removeEventListener('keyup', this.onKeyUp);
|
||||
|
||||
if (this.hasAttribute('open')) this.hide(false);
|
||||
}
|
||||
|
||||
observeOpener() {
|
||||
this.openerObserver?.disconnect();
|
||||
|
||||
if (!this.opener) return;
|
||||
|
||||
this.openerObserver = new MutationObserver(this.removeIfOpenerDisconnected);
|
||||
this.openerObserver.observe(document.body, { childList: true, subtree: true });
|
||||
this.removeIfOpenerDisconnected();
|
||||
}
|
||||
|
||||
removeIfOpenerDisconnected() {
|
||||
if (this.isMoving || !this.isConnected || this.opener?.isConnected) return;
|
||||
|
||||
this.remove();
|
||||
}
|
||||
|
||||
onOpenerClick(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.show();
|
||||
}
|
||||
|
||||
onCloseClick(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.hide();
|
||||
}
|
||||
|
||||
onModalClick(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
if (event.target === this) this.hide();
|
||||
}
|
||||
|
||||
onKeyUp(event) {
|
||||
if (event.code.toUpperCase() !== 'ESCAPE') return;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.hide();
|
||||
}
|
||||
|
||||
show() {
|
||||
if (this.hasAttribute('open')) return;
|
||||
|
||||
document.querySelectorAll('cart-disclosure-modal[open]').forEach((modal) => {
|
||||
if (modal !== this) modal.hide(false);
|
||||
});
|
||||
|
||||
this.lockScroll();
|
||||
this.setAttribute('open', '');
|
||||
this.opener?.setAttribute('aria-expanded', 'true');
|
||||
|
||||
if (typeof trapFocus === 'function') {
|
||||
trapFocus(this, this.dialog);
|
||||
} else {
|
||||
this.dialog?.focus();
|
||||
}
|
||||
|
||||
window.pauseAllMedia();
|
||||
}
|
||||
|
||||
hide(restoreFocus = true) {
|
||||
if (!this.hasAttribute('open')) return;
|
||||
|
||||
this.removeAttribute('open');
|
||||
this.opener?.setAttribute('aria-expanded', 'false');
|
||||
this.unlockScroll();
|
||||
|
||||
if (restoreFocus) {
|
||||
this.restoreFocusTrap();
|
||||
} else if (typeof removeTrapFocus === 'function') {
|
||||
removeTrapFocus();
|
||||
}
|
||||
|
||||
window.pauseAllMedia();
|
||||
}
|
||||
|
||||
lockScroll() {
|
||||
this.bodyOverflowWasHidden = document.body.classList.contains('overflow-hidden');
|
||||
this.previousBodyPaddingRight = document.body.style.paddingRight;
|
||||
|
||||
if (this.bodyOverflowWasHidden) return;
|
||||
|
||||
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
||||
|
||||
if (scrollbarWidth > 0) {
|
||||
const currentPaddingRight = parseFloat(window.getComputedStyle(document.body).paddingRight) || 0;
|
||||
document.body.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`;
|
||||
}
|
||||
|
||||
document.body.classList.add('overflow-hidden');
|
||||
}
|
||||
|
||||
unlockScroll() {
|
||||
if (this.bodyOverflowWasHidden) return;
|
||||
|
||||
document.body.classList.remove('overflow-hidden');
|
||||
document.body.style.paddingRight = this.previousBodyPaddingRight;
|
||||
}
|
||||
|
||||
restoreFocusTrap() {
|
||||
const cartDrawer = this.opener?.closest('cart-drawer.active');
|
||||
const cartNotification = this.opener?.closest('cart-notification')?.querySelector('#cart-notification.active');
|
||||
|
||||
if (cartDrawer && typeof trapFocus === 'function') {
|
||||
const containerToTrapFocusOn = cartDrawer.classList.contains('is-empty')
|
||||
? cartDrawer.querySelector('.drawer__inner-empty')
|
||||
: document.getElementById('CartDrawer');
|
||||
|
||||
if (containerToTrapFocusOn) {
|
||||
trapFocus(containerToTrapFocusOn, this.opener);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (cartNotification && typeof trapFocus === 'function') {
|
||||
trapFocus(cartNotification, this.opener);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof removeTrapFocus === 'function') {
|
||||
removeTrapFocus(this.opener);
|
||||
} else {
|
||||
this.opener?.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('cart-disclosure-modal', CartDisclosureModal);
|
||||
}
|
||||
Reference in New Issue
Block a user