@stormid/toggle
Version:
Accessible DOM state toggling
1 lines • 21.2 kB
Source Map (JSON)
{"version":3,"file":"index.modern.mjs","sources":["../src/lib/defaults.js","../src/lib/store.js","../src/lib/constants.js","../src/lib/dom.js","../src/lib/factory.js","../src/index.js","../src/lib/utils.js"],"sourcesContent":["/* istanbul ignore file */\n/*\n * Default settings used by a Toggle instance if not otherwise overwritten with config\n *\n * @property delay, Number, duration in milliseconds of toggle off process persisting animation state ('is--animating' on a global toggle) to support more granular off animations \n * @property startOpen, Boolean, toggle should start in an open state\n * @property local, Boolean, toggle is localised in the DOM (className changes are made to the parentNode, not the documentElement)\n * @property prehook, Function, called before each toggle event begins\n * @property callback, Function, called after each toggle event completes\n * @property focus, Boolean, focus should change to the first focusable child of a toggled element when opened\n * @property trapTab, Boolean, the toggled element should trap tab (tabbing from last child item returns focus to the first) when open\n * @property closeOnBlur, Boolean, the toggled element should close when focus moves to a non-child element\n * @property closeOnClick, Boolean, the toggled element should close when a non-child element is clicked\n * @property useHidden, Boolean, set to true to add the html 'hidden' attribute to the toggled element\n */\nexport default {\n delay: 0,\n startOpen: false,\n local: false,\n prehook: false,\n callback: false,\n focus: true,\n trapTab: false,\n closeOnBlur: false,\n closeOnClick: false,\n useHidden: false\n};","export const createStore = () => {\r\n let state = {};\r\n \r\n const getState = () => state;\r\n\r\n const update = (nextState, effects) => {\r\n state = nextState ?? state;\r\n if (!effects) return;\r\n effects.forEach(effect => effect(state));\r\n };\r\n \r\n return { update, getState };\r\n};","/* istanbul ignore file */\r\nexport const ACCEPTED_TRIGGERS = ['button', 'a'];\r\n\r\nexport const FOCUSABLE_ELEMENTS = ['a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', 'iframe', 'object', 'embed', '[contenteditable]', '[tabindex]:not([tabindex=\"-1\"])'];\r\n\r\nexport const EVENTS = {\r\n OPEN: 'toggle.open',\r\n CLOSE: 'toggle.close'\r\n};","import { FOCUSABLE_ELEMENTS, ACCEPTED_TRIGGERS, EVENTS } from './constants';\r\n\r\n/*\r\n * Partially applied function\r\n * Sets aria attributes and adds eventListener to each toggle button\r\n * \r\n * @param store, Object, model or state of the current instance\r\n * @returns Function\r\n */\r\nexport const initUI = store => () => {\r\n const { toggles, node, settings } = store.getState();\r\n if (settings.useHidden) node.hidden = true;\r\n toggles.forEach(toggle => {\r\n const id = node.getAttribute('id');\r\n if (toggle.tagName !== 'BUTTON') toggle.setAttribute('role', 'button');\r\n if (!id) throw console.warn(`The toggle target should have an id.`);\r\n toggle.setAttribute('aria-controls', id);\r\n toggle.setAttribute('aria-expanded', 'false');\r\n\r\n toggle.addEventListener('click', e => {\r\n e.preventDefault();\r\n startToggleLifecycle(store)();\r\n });\r\n });\r\n};\r\n\r\n/*\r\n * Partially applied function\r\n * Dispatches a toggle action to the store\r\n * \r\n * @param store, Object, model or state of the current instance\r\n * @returns Function\r\n */\r\nexport const toggle = store => () => {\r\n store.update({\r\n ...store.getState(),\r\n isOpen: !store.getState().isOpen\r\n },\r\n [ toggleAttributes, manageFocus(store), closeProxy(store), broadcast(store) ]\r\n );\r\n};\r\n\r\n/*\r\n * Partially applied function that returns a function that begins the toggle lifecycle (prehook > toggle > callback)\r\n * \r\n * @param store, Object, model or state of the current instance\r\n * @returns Function\r\n */\r\nexport const startToggleLifecycle = store => () => {\r\n const { node, toggles, settings, isOpen, classTarget, animatingClass } = store.getState();\r\n (settings.prehook && typeof settings.prehook === 'function') && settings.prehook({ node, toggles, isOpen });\r\n classTarget.classList.add(animatingClass);\r\n const fn = () => {\r\n toggle(store)();\r\n (!!settings.callback && typeof settings.callback === 'function') && settings.callback({ node, toggles, isOpen: store.getState().isOpen });\r\n };\r\n if (isOpen && +settings.delay > 0) window.setTimeout(fn, +settings.delay);\r\n else fn();\r\n};\r\n\r\n/*\r\n * Returns an Array of HTMLElements selected based on data-toggle attribute of a given node\r\n * \r\n * @param node, HTMLElement, node to be toggled\r\n * @return Array of HTMLElements\r\n */\r\nexport const findToggles = node => {\r\n\r\n const toggleSelector = node.getAttribute('data-toggle');\r\n const composeSelector = classSelector => ACCEPTED_TRIGGERS.map(sel => `${sel}.${classSelector}`).join(', ');\r\n\r\n const toggles = node.getAttribute('data-toggle') && [].slice.call(document.querySelectorAll(composeSelector(toggleSelector)));\r\n\r\n if (!toggles) console.warn(`Toggle cannot be initialised, no buttons or anchors found for ${node}. Does it have a data-toggle attribute that identifies toggle buttons?`);\r\n return toggles;\r\n};\r\n\r\n/*\r\n * Returns an Array of HTMLElements selected from parentNode based on whitelist FOCUSABLE_ELEMENTS constant\r\n * \r\n * @param node, HTMLElement, node to be toggled\r\n * @return Array of HTMLElements\r\n */\r\nexport const getFocusableChildren = node => [].slice.call(node.querySelectorAll(FOCUSABLE_ELEMENTS.join(',')));\r\n\r\n/*\r\n * Change toggle button attributes and node target classNames\r\n * \r\n * @param props, Object, composed of properties of current state required to accessibly change button and toggle attributes\r\n */\r\nexport const toggleAttributes = ({ toggles, isOpen, node, classTarget, animatingClass, statusClass, settings }) => {\r\n toggles.forEach(toggle => toggle.setAttribute('aria-expanded', isOpen));\r\n classTarget.classList.remove(animatingClass);\r\n classTarget.classList[isOpen ? 'add' : 'remove'](statusClass);\r\n if (settings.useHidden) node.hidden = !isOpen;\r\n};\r\n\r\n/*\r\n * Partially applied function that returns a handler function for keydown events when toggle is open\r\n * \r\n * @param store, Object, model or store of the current instance\r\n * @returns Function, keyboard event handler\r\n * \r\n * @param Event, document keydown event dispatched from document\r\n */\r\nexport const keyListener = store => e => {\r\n switch (e.keyCode){\r\n case 27:\r\n e.preventDefault();\r\n startToggleLifecycle(store);\r\n break;\r\n case 9:\r\n trapTab(store, e);\r\n break;\r\n }\r\n};\r\n\r\n/*\r\n * Checks activeElement and compares with array of focusable elements in target node\r\n * If shift is held focus set on the last focusable element\r\n * If last element, focus is set on the first element\r\n * \r\n * @param store, Object, model or store of the current instance\r\n * @param e, Event, document keydown event passed down from keyListener\r\n */\r\nconst trapTab = (store, e) => {\r\n const focusableChildren = store.getState().focusableChildren;\r\n const focusedIndex = focusableChildren.indexOf(document.activeElement);\r\n if (e.shiftKey && focusedIndex === 0) {\r\n e.preventDefault();\r\n focusableChildren[focusableChildren.length - 1].focus();\r\n } else if (!e.shiftKey && focusedIndex === focusableChildren.length - 1) {\r\n e.preventDefault();\r\n focusableChildren[0].focus();\r\n }\r\n};\r\n\r\n/*\r\n * Checks if the event was dispatched from a toggle button\r\n *\r\n * @param toggles, Array of toggle HTMLElements \r\n * @param target, event target\r\n * \r\n * @returns Boolean, true if event was dispatched from a toggle button\r\n * \r\n */\r\nconst targetIsToggle = (toggles, target) => toggles.reduce((acc, toggle) => {\r\n if (toggle === target|| toggle.contains(target)) acc = true;\r\n return acc;\r\n}, false);\r\n\r\n/*\r\n * Partially applied factory function that returns handlers for focusin events\r\n * Returned function is added as an eventListener when closeOnBlur option is true\r\n * \r\n * @param store, Object, model or store of the current instance\r\n * @returns Function, event handler\r\n * \r\n * @param Event, event dispatched from document\r\n */\r\nexport const focusInListener = store => e => {\r\n const state = store.getState();\r\n if (!state.node.contains(e.target) && !targetIsToggle(state.toggles, e.target)) toggle(store)();\r\n};\r\n\r\n/*\r\n * Partially applied factory function that returns handlers for focusin and click events\r\n * Returned function is added as an eventListener when closeOnClick options are true\r\n * \r\n * @param store, Object, model or store of the current instance\r\n * @returns Function, event handler\r\n * \r\n * @param Event, event dispatched from document\r\n */\r\nexport const clickListener = store => e => {\r\n const { node, toggles } = store.getState();\r\n if (node.contains(e.target) || targetIsToggle(toggles, e.target)) return;\r\n toggle(store)();\r\n};\r\n\r\n/*\r\n * Partially applied function that returns a function that adds and removes the document proxyListeners\r\n * Only added as an eventListener when closeOnBlur and/or closeOnClick options are true\r\n * \r\n * @param store, Object, model or state of the current instance\r\n */\r\nexport const closeProxy = store => () => {\r\n const { settings, isOpen, focusInListener, clickListener } = store.getState();\r\n if (settings.closeOnBlur) document[`${isOpen ? 'add' : 'remove'}EventListener`]('focusin', focusInListener);\r\n if (settings.closeOnClick) document[`${isOpen ? 'add' : 'remove'}EventListener`]('click', clickListener);\r\n};\r\n\r\n\r\n/*\r\n * Partially applied function that returns a function that sets up and pulls down focus event handlers based on toggle status and focus management options \r\n * \r\n * @param store, Object, model or state of the current instance\r\n */\r\nexport const manageFocus = store => () => {\r\n const { isOpen, focusableChildren, settings, lastFocused, keyListener } = store.getState();\r\n if ((!settings.focus && !settings.trapTab) || focusableChildren.length === 0) return;\r\n if (isOpen){\r\n store.update({ ...store.getState(), lastFocused: document.activeElement });\r\n const focusFn = () => focusableChildren[0].focus();\r\n if (settings.delay) window.setTimeout(focusFn, settings.delay);\r\n else focusFn();\r\n if (!settings.trapTab) return;\r\n settings.trapTab && document.addEventListener('keydown', keyListener);\r\n } else {\r\n if (!settings.trapTab) return;\r\n document.removeEventListener('keydown', keyListener);\r\n const reFocusFn = () => {\r\n lastFocused && lastFocused.focus();\r\n store.update({ ...store.getState(), lastFocused: false });\r\n };\r\n if (settings.delay) window.setTimeout(reFocusFn, settings.delay);\r\n else reFocusFn();\r\n }\r\n};\r\n\r\nexport const getStateFromDOM = (node, settings) => {\r\n const classTarget = settings.local ? node.parentNode : document.documentElement;\r\n const statusClass = settings.local ? 'is--active' : `on--${node.getAttribute('id')}`;\r\n return {\r\n classTarget,\r\n statusClass,\r\n shouldStartOpen: settings.startOpen || classTarget.classList.contains(statusClass)\r\n };\r\n};\r\n\r\nexport const broadcast = store => state => {\r\n const event = new CustomEvent(EVENTS[state.isOpen ? 'OPEN' : 'CLOSE'], {\r\n bubbles: true,\r\n detail: {\r\n getState: store.getState\r\n }\r\n });\r\n state.node.dispatchEvent(event);\r\n};","import { createStore } from './store';\r\nimport {\r\n findToggles,\r\n getFocusableChildren,\r\n keyListener,\r\n focusInListener,\r\n clickListener,\r\n initUI,\r\n startToggleLifecycle,\r\n toggle,\r\n getStateFromDOM\r\n} from './dom';\r\n\r\n\r\n/* \r\n * @param settings, Object, merged defaults + options\r\n * @param node, HTMLElement, DOM node to be toggled\r\n *\r\n * @returns Object, Toggle API\r\n */\r\nexport default ({ node, settings }) => {\r\n const store = createStore();\r\n //resolve state from DOM\r\n const { classTarget, statusClass, shouldStartOpen } = getStateFromDOM(node, settings);\r\n //set initial state of store\r\n store.update({\r\n node,\r\n settings,\r\n toggles: findToggles(node),\r\n isOpen: false,\r\n classTarget,\r\n statusClass,\r\n animatingClass: settings.local ? `animating--${node.getAttribute('id')}` : 'is--animating',\r\n focusableChildren: getFocusableChildren(node),\r\n lastFocused: false,\r\n keyListener: keyListener(store),\r\n focusInListener: focusInListener(store),\r\n clickListener: clickListener(store)\r\n }, [ initUI(store), () => {\r\n\t shouldStartOpen && startToggleLifecycle(store)();\r\n }]);\r\n\r\n\r\n return {\r\n node,\r\n startToggle: startToggleLifecycle(store),\r\n toggle: toggle(store),\r\n getState: store.getState\r\n };\r\n};","import defaults from './lib/defaults';\nimport factory from './lib/factory';\nimport { getSelection } from './lib/utils';\n\n/*\n * Returns an array of objects augmenting DOM elements that match a selector\n *\n * @param selector, Can be a string, Array of DOM nodes, a NodeList or a single DOM element.\n * @params options, Object, to be merged with defaults to become the settings propery of each returned object\n */\nexport default (selector, options) => {\n let nodes = getSelection(selector);\n\n if (nodes.length === 0) return console.warn(`Toggle not initialised, no elements found for selector '${selector}'`);\n \n //return array of Objects, one for each DOM node found\n //each Object has a prototype consisting of the node (HTMLElement),\n //and a settings property composed from defaults, data-attributes on the node, and options passed to init\n return nodes.map(node => Object.create(factory({\n settings: { ...defaults, ...options, ...node.dataset },\n node\n })));\n};","/*\r\n * Converts a selector of varying types into an array of DOM Objects\r\n *\r\n * @param selector, string, Array of DOM nodes, a NodeList or a single DOM element.\r\n */\r\nexport const getSelection = selector => {\r\n if (typeof selector === 'string') return [].slice.call(document.querySelectorAll(selector));\r\n if (selector instanceof Array) return selector;\r\n if (Object.prototype.isPrototypeOf.call(NodeList.prototype, selector)) return [].slice.call(selector);\r\n if (selector instanceof HTMLElement) return [selector];\r\n return [];\r\n};"],"names":["defaults","delay","startOpen","local","prehook","callback","focus","trapTab","closeOnBlur","closeOnClick","useHidden","ACCEPTED_TRIGGERS","FOCUSABLE_ELEMENTS","EVENTS","OPEN","CLOSE","initUI","store","toggles","node","settings","getState","hidden","forEach","toggle","id","getAttribute","tagName","setAttribute","console","warn","addEventListener","e","preventDefault","startToggleLifecycle","update","_extends","isOpen","toggleAttributes","manageFocus","closeProxy","broadcast","classTarget","animatingClass","classList","add","fn","window","setTimeout","findToggles","toggleSelector","slice","call","document","querySelectorAll","classSelector","map","sel","join","getFocusableChildren","statusClass","remove","keyListener","keyCode","focusableChildren","focusedIndex","indexOf","activeElement","shiftKey","length","targetIsToggle","target","reduce","acc","contains","focusInListener","state","clickListener","lastFocused","focusFn","removeEventListener","reFocusFn","event","CustomEvent","bubbles","detail","dispatchEvent","index","selector","options","nodes","Array","Object","prototype","isPrototypeOf","NodeList","HTMLElement","getSelection","create","createStore","nextState","effects","effect","shouldStartOpen","getStateFromDOM","parentNode","documentElement","startToggle","factory","dataset"],"mappings":"wNAeA,IAAAA,EAAe,CACXC,MAAO,EACPC,WAAW,EACXC,OAAO,EACPC,SAAS,EACTC,UAAU,EACVC,OAAO,EACPC,SAAS,EACTC,aAAa,EACbC,cAAc,EACdC,WAAW,GCzBF,MCCAC,EAAoB,CAAC,SAAU,KAE/BC,EAAqB,CAAC,UAAW,aAAc,wBAAyB,yBAA0B,2BAA4B,yBAA0B,SAAU,SAAU,QAAS,oBAAqB,mCAE1MC,EAAS,CAClBC,KAAM,cACNC,MAAO,gBCEEC,EAASC,GAAS,KAC3B,MAAMC,QAAEA,EAAOC,KAAEA,EAAIC,SAAEA,GAAaH,EAAMI,WACtCD,EAASV,YAAWS,EAAKG,QAAS,GACtCJ,EAAQK,QAAQC,IACZ,MAAMC,EAAKN,EAAKO,aAAa,MAE7B,GADuB,WAAnBF,EAAOG,SAAsBH,EAAOI,aAAa,OAAQ,WACxDH,EAAI,MAAMI,QAAQC,KAAK,wCAC5BN,EAAOI,aAAa,gBAAiBH,GACrCD,EAAOI,aAAa,gBAAiB,SAErCJ,EAAOO,iBAAiB,QAASC,IAC7BA,EAAEC,iBACFC,EAAqBjB,EAArBiB,EACJ,EACJ,EACJ,EASaV,EAASP,GAAS,KAC3BA,EAAMkB,OAAMC,EACLnB,CAAAA,EAAAA,EAAMI,YACTgB,QAASpB,EAAMI,WAAWgB,SAE9B,CAAEC,EAAkBC,EAAYtB,GAAQuB,EAAWvB,GAAQwB,EAAUxB,IACrE,EASSiB,EAAuBjB,GAAS,KACzC,MAAME,KAAEA,EAAID,QAAEA,EAAOE,SAAEA,EAAQiB,OAAEA,EAAMK,YAAEA,EAAWC,eAAEA,GAAmB1B,EAAMI,WAC9ED,EAAShB,SAAuC,mBAArBgB,EAAShB,SAA2BgB,EAAShB,QAAQ,CAAEe,OAAMD,UAASmB,WAClGK,EAAYE,UAAUC,IAAIF,GAC1B,MAAMG,EAAKA,KACPtB,EAAOP,EAAPO,GACGJ,EAASf,UAAyC,mBAAtBe,EAASf,UAA4Be,EAASf,SAAS,CAAEc,OAAMD,UAASmB,OAAQpB,EAAMI,WAAWgB,QACpI,EACIA,IAAWjB,EAASnB,MAAQ,EAAG8C,OAAOC,WAAWF,GAAK1B,EAASnB,OAC9D6C,GAAE,EASEG,EAAc9B,IAEvB,MAAM+B,EAAiB/B,EAAKO,aAAa,eAGnCR,EAAUC,EAAKO,aAAa,gBAAkB,GAAGyB,MAAMC,KAAKC,SAASC,kBAFnDC,EAEoFL,EAFnEvC,EAAkB6C,IAAIC,GAAO,GAAGA,KAAOF,KAAiBG,KAAK,SAA9EH,MAKxB,OADKrC,GAASW,QAAQC,KAAK,iEAAiEX,2EACrFD,GASEyC,EAAuBxC,GAAQ,GAAGgC,MAAMC,KAAKjC,EAAKmC,iBAAiB1C,EAAmB8C,KAAK,OAO3FpB,EAAmBA,EAAGpB,UAASmB,SAAQlB,OAAMuB,cAAaC,iBAAgBiB,cAAaxC,eAChGF,EAAQK,QAAQC,GAAUA,EAAOI,aAAa,gBAAiBS,IAC/DK,EAAYE,UAAUiB,OAAOlB,GAC7BD,EAAYE,UAAUP,EAAS,MAAQ,UAAUuB,GAC7CxC,EAASV,YAAWS,EAAKG,QAAUe,EAC3C,EAUayB,EAAc7C,GAASe,IAChC,OAAQA,EAAE+B,SACV,QACI/B,EAAEC,iBAEF,MACJ,KAAM,EACF1B,EAAQU,EAAOe,GAEnB,EAWEzB,EAAUA,CAACU,EAAOe,KACpB,MAAMgC,EAAoB/C,EAAMI,WAAW2C,kBACrCC,EAAeD,EAAkBE,QAAQb,SAASc,eACpDnC,EAAEoC,UAA6B,IAAjBH,GACdjC,EAAEC,iBACF+B,EAAkBA,EAAkBK,OAAS,GAAG/D,SACxC0B,EAAEoC,UAAYH,IAAiBD,EAAkBK,OAAS,IAClErC,EAAEC,iBACF+B,EAAkB,GAAG1D,QACzB,EAYEgE,EAAiBA,CAACpD,EAASqD,IAAWrD,EAAQsD,OAAO,CAACC,EAAKjD,MACzDA,IAAW+C,GAAS/C,EAAOkD,SAASH,MAASE,GAAM,GAChDA,IACR,GAWUE,EAAkB1D,GAASe,IACpC,MAAM4C,EAAQ3D,EAAMI,WACfuD,EAAMzD,KAAKuD,SAAS1C,EAAEuC,SAAYD,EAAeM,EAAM1D,QAASc,EAAEuC,SAAS/C,EAAOP,EAAPO,EAAa,EAYpFqD,EAAgB5D,GAASe,IAClC,MAAMb,KAAEA,EAAID,QAAEA,GAAYD,EAAMI,WAC5BF,EAAKuD,SAAS1C,EAAEuC,SAAWD,EAAepD,EAASc,EAAEuC,SACzD/C,EAAOP,EAAPO,EACJ,EAQagB,EAAavB,GAAS,KAC/B,MAAMG,SAAEA,EAAQiB,OAAEA,EAAMsC,gBAAEA,EAAeE,cAAEA,GAAkB5D,EAAMI,WAC/DD,EAASZ,aAAa6C,UAAYhB,EAAS,MAAQ,UAApB,iBAA6C,UAAWsC,GACvFvD,EAASX,cAAc4C,UAAYhB,EAAS,MAAQ,UAApB,iBAA6C,QAASwC,EAC9F,EAQatC,EAActB,GAAS,KAChC,MAAMoB,OAAEA,EAAM2B,kBAAEA,EAAiB5C,SAAEA,EAAQ0D,YAAEA,EAAWhB,YAAEA,GAAgB7C,EAAMI,WAChF,IAAMD,EAASd,OAAUc,EAASb,UAAyC,IAA7ByD,EAAkBK,OAChE,GAAIhC,EAAO,CACPpB,EAAMkB,OAAMC,KAAMnB,EAAMI,WAAYyD,CAAAA,YAAazB,SAASc,iBAC1D,MAAMY,EAAUA,IAAMf,EAAkB,GAAG1D,QAG3C,GAFIc,EAASnB,MAAO8C,OAAOC,WAAW+B,EAAS3D,EAASnB,OACnD8E,KACA3D,EAASb,QAAS,OACvBa,EAASb,SAAW8C,SAAStB,iBAAiB,UAAW+B,EAC7D,KAAO,CACH,IAAK1C,EAASb,QAAS,OACvB8C,SAAS2B,oBAAoB,UAAWlB,GACxC,MAAMmB,EAAYA,KACdH,GAAeA,EAAYxE,QAC3BW,EAAMkB,OAAMC,EAAMnB,CAAAA,EAAAA,EAAMI,WAAU,CAAEyD,aAAa,IAAO,EAExD1D,EAASnB,MAAO8C,OAAOC,WAAWiC,EAAW7D,EAASnB,OACrDgF,GACT,GAaSxC,EAAYxB,GAAS2D,IAC9B,MAAMM,EAAQ,IAAIC,YAAYtE,EAAO+D,EAAMvC,OAAS,OAAS,SAAU,CACnE+C,SAAS,EACTC,OAAQ,CACJhE,SAAUJ,EAAMI,YAGxBuD,EAAMzD,KAAKmE,cAAcJ,ICzN7B,ICVAK,EAAe,CAACC,EAAUC,KACtB,IAAIC,ECNoBF,IACA,iBAAbA,EAA8B,GAAGrC,MAAMC,KAAKC,SAASC,iBAAiBkC,IAC7EA,aAAoBG,MAAcH,EAClCI,OAAOC,UAAUC,cAAc1C,KAAK2C,SAASF,UAAWL,GAAkB,GAAGrC,MAAMC,KAAKoC,GACxFA,aAAoBQ,YAAoB,CAACR,GACtC,GDCKS,CAAaT,GAEzB,OAAqB,IAAjBE,EAAMrB,OAAqBxC,QAAQC,KAAK,2DAA2D0D,MAKhGE,EAAMlC,IAAIrC,GAAQyE,OAAOM,ODErB,GAAG/E,OAAMC,eACpB,MAAMH,EHrBiBkF,MACvB,IAAIvB,EAAQ,CAAE,EAUd,MAAO,CAAEzC,OANMA,CAACiE,EAAWC,KACvBzB,EAAiB,MAATwB,EAAAA,EAAaxB,EAChByB,GACLA,EAAQ9E,QAAQ+E,GAAUA,EAAO1B,GAAM,EAG1BvD,SARAA,IAAMuD,EAQG,EGUZuB,IAERzD,YAAEA,EAAWkB,YAAEA,EAAW2C,gBAAEA,GDqMPC,EAACrF,EAAMC,KAClC,MAAMsB,EAActB,EAASjB,MAAQgB,EAAKsF,WAAapD,SAASqD,gBAC1D9C,EAAcxC,EAASjB,MAAQ,aAAe,OAAOgB,EAAKO,aAAa,QAC7E,MAAO,CACHgB,cACAkB,cACA2C,gBAAiBnF,EAASlB,WAAawC,EAAYE,UAAU8B,SAASd,GAC1E,EC5MsD4C,CAAgBrF,EAAMC,GAoB5E,OAlBAH,EAAMkB,OAAO,CACThB,OACAC,WACAF,QAAS+B,EAAY9B,GACrBkB,QAAQ,EACRK,cACAkB,cACAjB,eAAgBvB,EAASjB,MAAQ,cAAcgB,EAAKO,aAAa,QAAU,gBAC3EsC,kBAAmBL,EAAqBxC,GACxC2D,aAAa,EACbhB,YAAaA,EAAY7C,GACzB0D,gBAAiBA,EAAgB1D,GACjC4D,cAAeA,EAAc5D,IAC9B,CAAED,EAAOC,GAAQ,KACnBsF,GAAmBrE,EAAqBjB,EAArBiB,EAA2B,IAIxC,CACHf,OACAwF,YAAazE,EAAqBjB,GAClCO,OAAQA,EAAOP,GACfI,SAAUJ,EAAMI,SACpB,EC9BuCuF,CAAQ,CAC3CxF,SAAQgB,KAAOpC,EAAayF,EAAYtE,EAAK0F,SAC7C1F,UACD"}