{"version":3,"file":"split-panel-section.min.js","mappings":"wZAEA,SAASA,EAAWC,GAClB,KAAMA,EAAMC,yBAAyBC,mBACnC,OAKF,MAAMC,EAAUH,EAAMC,cAAcG,QAAQ,uBACtCC,EAAOF,EAAQG,iBAAoC,gBACnDC,EAASJ,EAAQG,iBAA8B,qBAErD,IAAK,MAAME,KAAOH,EAChBG,EAAIC,aAAa,gBAAiB,SAGpC,IAAK,MAAMC,KAASH,EAClBG,EAAMC,QAAS,EAGjBX,EAAMC,cAAcQ,aAAa,gBAAiB,QAClD,MAAMG,EAAUZ,EAAMC,cAAcY,aAAa,iBAC3BV,EAAQW,cAA2B,IAAMF,GACjDD,QAAS,CACzB,CAEA,SAASI,EAAYZ,GAEnB,IADgBA,EAAQW,cAAc,oBAEpC,OAGF,MAAMT,EAAOF,EAAQG,iBAAoC,gBAEzD,IAAK,MAAME,KAAOH,EAChBG,EAAIQ,iBAAiB,QAASjB,EAElC,ECoBO,SAAekB,EACpBC,GACA,QAD2B,IAA3BA,IAAAA,EAA8B,oBACF,aAAxBC,SAASC,YAAuC,qBAATF,GACjB,gBAAxBC,SAASC,WAA+B,CACxC,MAAMC,EAAQC,WAAWL,EAAU,GAEnC,MAD8B,IAAMM,aAAaF,EAEnD,CACEL,iBAAiBE,EAAMD,EAI3B,CDpBAO,CAVA,WAGE,MAAMC,EAAWN,SAASb,iBAA8B,yCACxD,IAAK,MAAMH,KAAWsB,EACpBV,EAAYZ,GACZA,EAAQuB,UAAUC,IAAI,cAE1B","sources":["webpack://lange/./sections/split-panel/index.ts","webpack://lange/./lib/dom-ready.ts"],"sourcesContent":["import { ready } from '../../lib/dom-ready.js';\n\nfunction onTabClick(event: MouseEvent) {\n  if (!(event.currentTarget instanceof HTMLButtonElement)) {\n    return;\n  }\n\n  // This section is rendered dynamically and can repeat on a page. We resolve the specific instance\n  // by climbing from the clicked control rather than by a wrapper id.\n  const section = event.currentTarget.closest('section.split-panel');\n  const tabs = section.querySelectorAll<HTMLButtonElement>('[role=\"tab\"]');\n  const panels = section.querySelectorAll<HTMLElement>('[role=\"tabpanel\"]');\n\n  for (const tab of tabs) {\n    tab.setAttribute('aria-selected', 'false');\n  }\n\n  for (const panel of panels) {\n    panel.hidden = true;\n  }\n\n  event.currentTarget.setAttribute('aria-selected', 'true');\n  const panelId = event.currentTarget.getAttribute('aria-controls');\n  const selectedPanel = section.querySelector<HTMLElement>('#' + panelId);\n  selectedPanel.hidden = false;\n}\n\nfunction initSection(section: HTMLElement) {\n  const tablist = section.querySelector('[role=\"tablist\"]');\n  if (!tablist) {\n    return;\n  }\n\n  const tabs = section.querySelectorAll<HTMLButtonElement>('[role=\"tab\"]');\n\n  for (const tab of tabs) {\n    tab.addEventListener('click', onTabClick);\n  }\n}\n\nfunction onReady() {\n  // This section is rendered dynamically and may appear several times per page. We iterate every\n  // instance rather than do a single id lookup.\n  const sections = document.querySelectorAll<HTMLElement>('section.split-panel:not(.initialized)');\n  for (const section of sections) {\n    initSection(section);\n    section.classList.add('initialized');\n  }\n}\n\nready(onReady);\n","/**\n * Releases the handle returned from the ready() function.\n *\n * This is idempotent. Additional calls are pointless but harmless.\n */\nexport type ReleaseHandle = () => void;\n\n/**\n * A subset of events that pertain to document ready state.\n */\ntype LoadingEventMap = Pick<DocumentEventMap, 'DOMContentLoaded' | 'load'>;\n\n/**\n * Calls the provided callback when the document is ready. This works both when the document is\n * already ready and when it is not, so callers do not have to care. This exists because it ensures\n * that each caller consistently expresses its dependency on document readiness, and to save a bit\n * of boilerplate.\n *\n * A document is considered ready when it has been parsed. This corresponds to the ready state of\n * 'interactive'. When the document has been fully loaded, the ready state is 'complete'. The\n * callback runs either way, so callers do not have to check which one they are in.\n *\n * Ready means the html is parsed and the DOM is there to query. It does not mean the page's other\n * scripts have run. Deferred scripts and module scripts run after the ready state turns\n * 'interactive' and before DOMContentLoaded fires, so a callback here can run before them. When a\n * caller needs some other script to have run already, this is the wrong tool, and it should wait on\n * whatever that script produces instead.\n *\n * That remedy has a catch of its own when the calling bundle is loaded with async. An async bundle\n * can execute after DOMContentLoaded has already fired, so a plain listener for that event never\n * runs and the work silently never happens. Nothing here can detect that, because by the time this\n * file executes the event is long gone. Catching it needs something registered at parse time,\n * before any bundle loads.\n *\n * There is a second trap right next to that one, and it applies only when waiting for\n * DOMContentLoaded. The ready state stays 'interactive' after DOMContentLoaded has fired, all the\n * way until 'complete', so the ready state cannot tell you whether DOMContentLoaded is still coming\n * or has already gone. Waiting for load is not exposed to this, because the ready state turns\n * 'complete' and load fires in the same task, so seeing 'complete' means load has fired too.\n *\n * When the document is already ready, the callback is invoked via setTimeout. This way, if the\n * callback throws, the error surfaces to the global error handler in a way that is similar to what\n * happens when an event listener throws.\n *\n * We might one day want to move this to an NPM library.\n *\n * Beware of a quirk here. setTimeout yields, and the busier the frontend, the longer it takes to\n * fire. Page load is exactly when the frontend is busiest. The timeout is a floor and not a\n * guarantee, so there is no real bound on how long that yield lasts. What this means is that using\n * this library can introduce more delay than you might expect. Compare code that runs on async load\n * and checks ready state and invokes immediately to code that runs after setTimeout. The former\n * runs in the same tick, the latter runs in \"some later tick\". That later tick can be surprisingly\n * much later. That can cause initial paint issues.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event\n * @see https://html.spec.whatwg.org/multipage/parsing.html#the-end\n */\nexport function ready(callback: (event?: Event) => void,\n  type: keyof LoadingEventMap = 'DOMContentLoaded') {\n  if (document.readyState === 'complete' || (type === 'DOMContentLoaded' &&\n    document.readyState === 'interactive')) {\n    const timer = setTimeout(callback, 0);\n    const handle: ReleaseHandle = () => clearTimeout(timer);\n    return handle;\n  } else {\n    addEventListener(type, callback);\n    const handle: ReleaseHandle = () => removeEventListener(type, callback);\n    return handle;\n  }\n}\n"],"names":["onTabClick","event","currentTarget","HTMLButtonElement","section","closest","tabs","querySelectorAll","panels","tab","setAttribute","panel","hidden","panelId","getAttribute","querySelector","initSection","addEventListener","callback","type","document","readyState","timer","setTimeout","clearTimeout","ready","sections","classList","add"],"sourceRoot":""}