inspector.ts (2112B)
1 // A docked inspector on wide screens, an accessible modal sheet on phones. 2 export function setupInspector(): void { 3 const panel = document.getElementById('settings-panel')!, toggle = document.getElementById('settings-toggle')!; 4 const close = document.getElementById('settings-close')!, backdrop = document.getElementById('settings-backdrop')!; 5 const body = document.getElementById('editor-body')!, mobile = matchMedia('(max-width:740px)'); 6 const background = [...document.querySelectorAll<HTMLElement>('[data-inspector-background]')]; 7 let open = false; 8 function layout(): void { 9 panel.hidden = !open; backdrop.hidden = !open || !mobile.matches; 10 body.classList.toggle('settings-open', open); 11 toggle.setAttribute('aria-expanded', String(open)); 12 panel.setAttribute('role', mobile.matches ? 'dialog' : 'region'); 13 if (mobile.matches && open) panel.setAttribute('aria-modal', 'true'); else panel.removeAttribute('aria-modal'); 14 for (const element of background) element.inert = open && mobile.matches; 15 document.body.classList.toggle('inspector-modal', open && mobile.matches); 16 if (open && mobile.matches && !panel.contains(document.activeElement)) close.focus(); 17 } 18 function hide(): void { open = false; layout(); toggle.focus(); } 19 toggle.onclick = () => { if (open) hide(); else { open = true; layout(); close.focus(); } }; 20 close.onclick = backdrop.onclick = hide; 21 mobile.addEventListener('change', layout); 22 panel.addEventListener('keydown', event => { 23 if (event.key === 'Escape') { event.preventDefault(); hide(); } 24 if (event.key !== 'Tab' || !mobile.matches) return; 25 const items = [...panel.querySelectorAll<HTMLElement>('button,input,select,textarea,a[href],summary,[tabindex="0"]')] 26 .filter(e => !e.hasAttribute('disabled') && e.getClientRects().length > 0); 27 const first = items[0], last = items.at(-1); 28 if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last?.focus(); } 29 else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first?.focus(); } 30 }); 31 layout(); 32 }