팝업창 제목 스타일 적용, 단축키 추가
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
export function initModalControls() {
|
||||
document.addEventListener('click', e => {
|
||||
const closeBtn = e.target.closest('.modal-close');
|
||||
if (!closeBtn) return;
|
||||
|
||||
const modal = closeBtn.closest('.modal-overlay');
|
||||
if (!modal) return;
|
||||
|
||||
closeModal(modal);
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', e => {
|
||||
const modal = getActiveModal();
|
||||
if (!modal) return;
|
||||
|
||||
if (e.code === 'Escape') {
|
||||
const closeBtn = modal.querySelector('.modal-close');
|
||||
if (!closeBtn) return;
|
||||
e.preventDefault();
|
||||
closeBtn.click();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.code === 'Enter') {
|
||||
const actionBtn = modal.querySelector('.modal-action');
|
||||
if (!actionBtn) return;
|
||||
e.preventDefault();
|
||||
actionBtn.click();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.code === 'Tab') {
|
||||
trapFocus(e, modal);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function openModal(modal) {
|
||||
modal.style.display = 'flex';
|
||||
const primaryBtn = modal.querySelector('.modal-action');
|
||||
const closeBtn = modal.querySelector('.modal-close');
|
||||
(primaryBtn || closeBtn)?.focus();
|
||||
}
|
||||
|
||||
export function closeModal(modal) {
|
||||
modal.style.display = 'none';
|
||||
modal.dispatchEvent(new CustomEvent('modal:closed'));
|
||||
}
|
||||
|
||||
function getActiveModal() {
|
||||
const modals = [...document.querySelectorAll('.modal-overlay')];
|
||||
return modals.find(modal => modal.style.display === 'flex') || null;
|
||||
}
|
||||
|
||||
function trapFocus(e, modal) {
|
||||
const focusable = getFocusableElements(modal);
|
||||
if (!focusable.length) {
|
||||
e.preventDefault();
|
||||
modal.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const first = focusable[0];
|
||||
const last = focusable[focusable.length - 1];
|
||||
const active = document.activeElement;
|
||||
|
||||
if (!modal.contains(active)) {
|
||||
e.preventDefault();
|
||||
first.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.shiftKey && active === first) {
|
||||
e.preventDefault();
|
||||
last.focus();
|
||||
} else if (!e.shiftKey && active === last) {
|
||||
e.preventDefault();
|
||||
first.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function getFocusableElements(container) {
|
||||
const selector = [
|
||||
'button:not([disabled])',
|
||||
'input:not([disabled])',
|
||||
'select:not([disabled])',
|
||||
'textarea:not([disabled])',
|
||||
'a[href]',
|
||||
'[tabindex]:not([tabindex="-1"])',
|
||||
].join(',');
|
||||
|
||||
return [...container.querySelectorAll(selector)]
|
||||
.filter(el => !el.hidden && el.offsetParent !== null);
|
||||
}
|
||||
Reference in New Issue
Block a user