tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

inspector.js (2365B)


      1 // A docked inspector on wide screens, an accessible modal sheet on phones.
      2 export function setupInspector() {
      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('[data-inspector-background]')];
      7     let open = false;
      8     function layout() {
      9         panel.hidden = !open;
     10         backdrop.hidden = !open || !mobile.matches;
     11         body.classList.toggle('settings-open', open);
     12         toggle.setAttribute('aria-expanded', String(open));
     13         panel.setAttribute('role', mobile.matches ? 'dialog' : 'region');
     14         if (mobile.matches && open)
     15             panel.setAttribute('aria-modal', 'true');
     16         else
     17             panel.removeAttribute('aria-modal');
     18         for (const element of background)
     19             element.inert = open && mobile.matches;
     20         document.body.classList.toggle('inspector-modal', open && mobile.matches);
     21         if (open && mobile.matches && !panel.contains(document.activeElement))
     22             close.focus();
     23     }
     24     function hide() { open = false; layout(); toggle.focus(); }
     25     toggle.onclick = () => { if (open)
     26         hide();
     27     else {
     28         open = true;
     29         layout();
     30         close.focus();
     31     } };
     32     close.onclick = backdrop.onclick = hide;
     33     mobile.addEventListener('change', layout);
     34     panel.addEventListener('keydown', event => {
     35         if (event.key === 'Escape') {
     36             event.preventDefault();
     37             hide();
     38         }
     39         if (event.key !== 'Tab' || !mobile.matches)
     40             return;
     41         const items = [...panel.querySelectorAll('button,input,select,textarea,a[href],summary,[tabindex="0"]')]
     42             .filter(e => !e.hasAttribute('disabled') && e.getClientRects().length > 0);
     43         const first = items[0], last = items.at(-1);
     44         if (event.shiftKey && document.activeElement === first) {
     45             event.preventDefault();
     46             last?.focus();
     47         }
     48         else if (!event.shiftKey && document.activeElement === last) {
     49             event.preventDefault();
     50             first?.focus();
     51         }
     52     });
     53     layout();
     54 }