tabs.ts (1637B)
1 type Pane = 'how' | 'playground' | 'export-definition'; 2 const tabs = [...document.querySelectorAll<HTMLButtonElement>('[role="tab"]')]; 3 export function activePane(): Pane { 4 return (tabs.find(tab => tab.getAttribute('aria-selected') === 'true')?.dataset['pane'] ?? 'how') as Pane; 5 } 6 function activate(pane: Pane, focus = false): void { 7 const changed = activePane() !== pane; 8 for (const tab of tabs) { 9 const selected = tab.dataset['pane'] === pane; 10 tab.setAttribute('aria-selected', String(selected)); tab.tabIndex = selected ? 0 : -1; 11 const panel = document.getElementById(tab.getAttribute('aria-controls')!)!; 12 panel.classList.toggle('is-active', selected); panel.inert = !selected; 13 panel.setAttribute('aria-hidden', String(!selected)); 14 if (selected && focus) tab.focus(); 15 } 16 if (changed) window.dispatchEvent(new CustomEvent('pane-change', { detail: pane })); 17 } 18 for (const [index, tab] of tabs.entries()) { 19 tab.onclick = () => activate(tab.dataset['pane'] as Pane); 20 tab.onkeydown = event => { 21 const target = event.key === 'ArrowRight' ? (index + 1) % tabs.length 22 : event.key === 'ArrowLeft' ? (index + tabs.length - 1) % tabs.length 23 : event.key === 'Home' ? 0 : event.key === 'End' ? tabs.length - 1 : undefined; 24 if (target !== undefined) { event.preventDefault(); activate(tabs[target]!.dataset['pane'] as Pane, true); } 25 }; 26 } 27 for (const link of document.querySelectorAll<HTMLAnchorElement>('a[data-open-pane]')) link.onclick = () => { 28 activate(link.dataset['openPane'] as Pane); 29 }; 30 // Selection links are metadata, not permission to enter an execution pane. 31 activate('how');