slim-select 4.0.6 → 4.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"slimselect.iife.js","names":[],"sources":["../src/slim-select/classes.ts","../src/slim-select/animations.ts","../src/slim-select/settings.ts","../src/slim-select/helpers.ts","../src/slim-select/events.ts","../src/slim-select/lifecycle.ts","../src/slim-select/store.ts","../src/slim-select/render.ts","../src/slim-select/mutations.ts","../src/slim-select/select.ts","../src/slim-select/sync.ts","../src/slim-select/index.ts","../src/slim-select/index.umd.ts"],"sourcesContent":["export default class CssClasses {\n public main: string\n // Placeholder\n public placeholder: string\n\n // Values\n public values: string\n public single: string\n public multiString: string\n public max: string\n public value: string\n public valueText: string\n public valueDelete: string\n public valueOut: string\n\n // Deselect\n public deselect: string\n public deselectPath: string // Not a class but whatever\n\n // Arrow\n public arrow: string\n public arrowClose: string // Not a class but whatever\n public arrowOpen: string // Not a class but whatever\n\n // Content\n public content: string\n public contentOpen: string\n public dirAbove: string\n public dirBelow: string\n\n // Search\n public search: string\n public searchHighlighter: string\n public searching: string\n public status: string\n public addable: string\n public addablePath: string // Not a class but whatever\n\n // List optgroups/options\n public list: string\n\n // Optgroup\n public optgroup: string\n public optgroupLabel: string\n public optgroupLabelText: string\n public optgroupActions: string\n public optgroupSelectAll: string // optgroup select all\n public optgroupSelectAllBox: string // Not a class but whatever\n public optgroupSelectAllCheck: string // Not a class but whatever\n public optgroupClosable: string\n\n // Option\n public option: string\n public optionDelete: string // Not a class but whatever\n public highlighted: string\n\n // Modal\n public modalOverlay: string\n public modalDialog: string\n public modalTitle: string\n public modalClose: string\n public modalContent: string\n\n // Misc\n public mainOpen: string\n public close: string\n public selected: string\n public error: string\n public disabled: string\n public hide: string\n\n constructor(classes?: Partial<CssClasses>) {\n if (!classes) {\n classes = {}\n }\n\n let join = (a = '', b = '') => `${a} ${b}`.trim()\n\n this.main = join('ss-main', classes.main)\n this.placeholder = join('ss-placeholder', classes.placeholder)\n this.values = join('ss-values', classes.values)\n this.single = join('ss-single', classes.single)\n this.multiString = join('ss-multi-string', classes.multiString)\n this.max = join('ss-max', classes.max)\n this.value = join('ss-value', classes.value)\n this.valueText = join('ss-value-text', classes.valueText)\n this.valueDelete = join('ss-value-delete', classes.valueDelete)\n this.valueOut = join('ss-value-out', classes.valueOut)\n\n this.deselect = join('ss-deselect', classes.deselect)\n this.deselectPath = classes.deselectPath || 'M10,10 L90,90 M10,90 L90,10'\n this.arrow = join('ss-arrow', classes.arrow)\n this.arrowClose = classes.arrowClose || 'M10,30 L50,70 L90,30'\n this.arrowOpen = classes.arrowOpen || 'M10,70 L50,30 L90,70'\n this.content = join('ss-content', classes.content)\n this.contentOpen = join('ss-open', classes.contentOpen)\n this.dirAbove = join('ss-dir-above', classes.dirAbove)\n this.dirBelow = join('ss-dir-below', classes.dirBelow)\n this.search = join('ss-search', classes.search)\n this.searchHighlighter = join(\n 'ss-search-highlight',\n classes.searchHighlighter\n )\n this.searching = join('ss-searching', classes.searching)\n this.status = join('ss-status', classes.status)\n this.addable = join('ss-addable', classes.addable)\n this.addablePath = classes.addablePath || 'M50,10 L50,90 M10,50 L90,50'\n this.list = join('ss-list', classes.list)\n this.optgroup = join('ss-optgroup', classes.optgroup)\n this.optgroupLabel = join('ss-optgroup-label', classes.optgroupLabel)\n this.optgroupLabelText = join(\n 'ss-optgroup-label-text',\n classes.optgroupLabelText\n )\n this.optgroupActions = join('ss-optgroup-actions', classes.optgroupActions)\n this.optgroupSelectAll = join('ss-selectall', classes.optgroupSelectAll)\n this.optgroupSelectAllBox =\n classes.optgroupSelectAllBox || 'M60,10 L10,10 L10,90 L90,90 L90,50'\n this.optgroupSelectAllCheck =\n classes.optgroupSelectAllCheck || 'M30,45 L50,70 L90,10'\n this.optgroupClosable = join('ss-closable', classes.optgroupClosable)\n this.option = join('ss-option', classes.option)\n this.optionDelete = classes.optionDelete || 'M10,10 L90,90 M10,90 L90,10'\n this.highlighted = join('ss-highlighted', classes.highlighted)\n this.modalOverlay = join('ss-modal-overlay', classes.modalOverlay)\n this.modalDialog = join('ss-modal-dialog', classes.modalDialog)\n this.modalTitle = join('ss-modal-title', classes.modalTitle)\n this.modalClose = join('ss-modal-close', classes.modalClose)\n this.modalContent = join('ss-modal-content', classes.modalContent)\n this.mainOpen = join('ss-open', classes.mainOpen)\n this.close = join('ss-close', classes.close)\n this.selected = join('ss-selected', classes.selected)\n this.error = join('ss-error', classes.error)\n this.disabled = join('ss-disabled', classes.disabled)\n this.hide = join('ss-hide', classes.hide)\n }\n\n public getFirst(name: keyof Omit<CssClasses, 'getFirst'>): string {\n return this[name].split(' ')[0]\n }\n}\n","/**\n * Animation timing helpers.\n *\n * CSS still runs the motion — these keep lifecycle and DOM cleanup aligned with\n * --ss-animation-timing so we are not guessing with hardcoded setTimeout values.\n */\n\n/** Matches default --ss-animation-timing in slimselect.scss */\nconst DEFAULT_DURATION_MS = 200\n\n/** Extra ms added to CSS duration for transitionend/animationend safety-net timeouts. */\nexport const ANIMATION_TIMEOUT_BUFFER_MS = 50\n\n/** .ss-content open/close transitions — wait for both before lifecycle continues. */\nexport const CONTENT_PANEL_TRANSITION_PROPERTIES = [\n 'transform',\n 'opacity'\n] as const\n\n/** Parse a CSS time value (e.g. \"0.2s\", \"200ms\") into milliseconds. */\nexport function parseAnimationDuration(\n cssValue: string,\n fallback = DEFAULT_DURATION_MS\n): number {\n const trimmed = cssValue.trim()\n if (!trimmed) {\n return fallback\n }\n\n if (trimmed.endsWith('ms')) {\n const ms = parseFloat(trimmed)\n return Number.isNaN(ms) ? fallback : ms\n }\n\n if (trimmed.endsWith('s')) {\n const seconds = parseFloat(trimmed)\n return Number.isNaN(seconds) ? fallback : seconds * 1000\n }\n\n const numeric = parseFloat(trimmed)\n return Number.isNaN(numeric) ? fallback : numeric\n}\n\n/** Read --ss-animation-timing from an element's computed styles. */\nexport function getAnimationDuration(\n element: HTMLElement,\n fallback = DEFAULT_DURATION_MS\n): number {\n const computedStyle = getComputedStyle(element)\n const cssValue = computedStyle\n .getPropertyValue('--ss-animation-timing')\n .trim()\n return parseAnimationDuration(cssValue, fallback)\n}\n\n/**\n * Safety-net timeout for animation waits.\n * Derived from --ss-animation-timing (+ buffer). An explicit settings.timeoutDelay\n * is treated as a minimum — never shorter than the CSS-driven duration.\n */\nexport function getAnimationTimeout(\n element: HTMLElement,\n userTimeout?: number,\n fallback = DEFAULT_DURATION_MS\n): number {\n const fromCss =\n getAnimationDuration(element, fallback) + ANIMATION_TIMEOUT_BUFFER_MS\n\n if (userTimeout === undefined) {\n return fromCss\n }\n\n return Math.max(fromCss, userTimeout)\n}\n\n/** Respect user OS accessibility preference and jsdom (no matchMedia). */\nexport function prefersReducedMotion(): boolean {\n if (\n typeof window === 'undefined' ||\n typeof window.matchMedia !== 'function'\n ) {\n return false\n }\n\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches\n}\n\nfunction normalizeTransitionProperties(\n propertyNames?: string | readonly string[]\n): Set<string> | null {\n if (propertyNames === undefined) {\n return null\n }\n\n const list = Array.isArray(propertyNames) ? propertyNames : [propertyNames]\n return new Set(list)\n}\n\n/**\n * Wait for CSS transition(s) to finish, with a timeout fallback.\n *\n * Pass a single property name to resolve on that transitionend, or an array to\n * wait until every listed property has fired (e.g. transform + opacity on .ss-content).\n * Optional AbortSignal cleans up listeners when lifecycle cancels a rapid toggle.\n */\nexport function waitForTransitionEnd(\n element: HTMLElement,\n propertyNames?: string | readonly string[],\n timeoutMs = DEFAULT_DURATION_MS,\n signal?: AbortSignal\n): Promise<void> {\n if (prefersReducedMotion() || signal?.aborted) {\n return Promise.resolve()\n }\n\n const pending = normalizeTransitionProperties(propertyNames)\n\n return new Promise<void>((resolve) => {\n let timer: ReturnType<typeof setTimeout> | null = null\n let settled = false\n\n const finish = () => {\n if (settled) {\n return\n }\n settled = true\n element.removeEventListener('transitionend', onTransitionEnd)\n signal?.removeEventListener('abort', onAbort)\n if (timer) {\n clearTimeout(timer)\n }\n resolve()\n }\n\n const onAbort = () => finish()\n\n const onTransitionEnd = (event: TransitionEvent) => {\n if (event.target !== element) {\n return\n }\n\n if (pending) {\n if (!pending.has(event.propertyName)) {\n return\n }\n pending.delete(event.propertyName)\n if (pending.size > 0) {\n return\n }\n }\n\n finish()\n }\n\n signal?.addEventListener('abort', onAbort, { once: true })\n element.addEventListener('transitionend', onTransitionEnd)\n timer = setTimeout(finish, timeoutMs)\n })\n}\n\n/**\n * Wait for a CSS @keyframes animation to finish, with a timeout fallback.\n *\n * Used when removing multi-select value chips (.ss-value-out). jsdom does not\n * fire animationend, so the timeout wins in unit tests.\n */\nexport function waitForAnimationEnd(\n element: HTMLElement,\n animationName?: string,\n timeoutMs = DEFAULT_DURATION_MS,\n signal?: AbortSignal\n): Promise<void> {\n if (prefersReducedMotion() || signal?.aborted) {\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve) => {\n let timer: ReturnType<typeof setTimeout> | null = null\n let settled = false\n\n const finish = () => {\n if (settled) {\n return\n }\n settled = true\n element.removeEventListener('animationend', onAnimationEnd)\n signal?.removeEventListener('abort', onAbort)\n if (timer) {\n clearTimeout(timer)\n }\n resolve()\n }\n\n const onAbort = () => finish()\n\n const onAnimationEnd = (event: AnimationEvent) => {\n if (event.target !== element) {\n return\n }\n if (animationName && event.animationName !== animationName) {\n return\n }\n finish()\n }\n\n signal?.addEventListener('abort', onAbort, { once: true })\n element.addEventListener('animationend', onAnimationEnd)\n timer = setTimeout(finish, timeoutMs)\n })\n}\n","import { generateID } from './helpers'\n\nexport type ModalSetting = 'off' | 'on' | 'mobile'\n\nexport const MODAL_MOBILE_BREAKPOINT = 768\n\nexport default class Settings {\n public id: string = '' // Primary ID for the select\n public style: string = '' // Style attribute from the select element\n public class: string[] = [] // Class attribute from the select element\n\n // Dynamic settings\n public isMultiple: boolean = false\n public isOpen: boolean = false\n public isFullOpen: boolean = false\n\n // Fields set from constructor\n public disabled: boolean\n public alwaysOpen: boolean\n public showSearch: boolean\n public focusSearch: boolean\n public keepSearch: boolean\n public ariaLabel: string\n public searchPlaceholder: string\n public searchText: string\n public searchingText: string\n public resultsText: string\n public deselectText: string\n public removeText: string\n public searchHighlight: boolean\n public closeOnSelect: boolean\n public contentLocation: HTMLElement | null\n public contentPosition: 'relative' | 'absolute' | 'fixed'\n public contentWidth: string\n public openPosition: 'auto' | 'up' | 'down'\n public placeholderText: string\n public allowDeselect: boolean\n public hideSelected: boolean\n public multiString: boolean\n public keepOrder: boolean\n public showOptionTooltips: boolean\n public minSelected: number\n public maxSelected: number\n public timeoutDelay: number\n public maxValuesShown: number\n public maxValuesMessage: string\n public addableText: string\n public modal: ModalSetting\n public modalTitle: string\n\n constructor(settings?: Partial<Settings>) {\n if (!settings) {\n settings = {}\n }\n\n this.id = 'ss-' + generateID()\n this.style = settings.style || ''\n this.class = settings.class || []\n\n this.disabled = settings.disabled !== undefined ? settings.disabled : false\n this.alwaysOpen =\n settings.alwaysOpen !== undefined ? settings.alwaysOpen : false\n this.showSearch =\n settings.showSearch !== undefined ? settings.showSearch : true\n this.focusSearch =\n settings.focusSearch !== undefined ? settings.focusSearch : true\n this.keepSearch =\n settings.keepSearch !== undefined ? settings.keepSearch : false\n this.ariaLabel = settings.ariaLabel || 'Combobox'\n this.searchPlaceholder = settings.searchPlaceholder || 'Search...'\n this.searchText = settings.searchText || 'No Results'\n this.searchingText = settings.searchingText || 'Searching...'\n this.resultsText = settings.resultsText || '{count} results available'\n this.deselectText = settings.deselectText || 'Clear'\n this.removeText = settings.removeText || 'Remove'\n this.searchHighlight =\n settings.searchHighlight !== undefined ? settings.searchHighlight : false\n this.closeOnSelect =\n settings.closeOnSelect !== undefined ? settings.closeOnSelect : true\n this.contentLocation = settings.contentLocation || document.body\n this.contentPosition = settings.contentPosition || 'absolute'\n this.contentWidth = settings.contentWidth || ''\n this.openPosition = settings.openPosition || 'auto' // options: auto, up, down\n this.placeholderText =\n settings.placeholderText !== undefined\n ? settings.placeholderText\n : 'Select Value'\n this.allowDeselect =\n settings.allowDeselect !== undefined ? settings.allowDeselect : false\n this.hideSelected =\n settings.hideSelected !== undefined ? settings.hideSelected : false\n this.multiString =\n settings.multiString !== undefined ? settings.multiString : false\n this.keepOrder =\n settings.keepOrder !== undefined ? settings.keepOrder : false\n this.showOptionTooltips =\n settings.showOptionTooltips !== undefined\n ? settings.showOptionTooltips\n : false\n this.minSelected = settings.minSelected || 0\n this.maxSelected = settings.maxSelected || 1000\n this.timeoutDelay = settings.timeoutDelay || 200 // Default until SlimSelect reads --ss-animation-timing\n this.maxValuesShown = settings.maxValuesShown || 20\n this.maxValuesMessage = settings.maxValuesMessage || '{number} selected'\n this.addableText = settings.addableText || 'Press \"Enter\" to add {value}'\n this.modal = settings.modal || 'mobile'\n this.modalTitle = settings.modalTitle || ''\n }\n}\n","import type { Optgroup, Option } from './store'\nimport { MODAL_MOBILE_BREAKPOINT, type ModalSetting } from './settings'\n\ntype DataItem = Partial<Option> | Partial<Optgroup>\n\n/** Copy option data attributes into a plain object (not a live DOMStringMap). */\nexport function copyOptionData(\n data?: { [key: string]: string } | DOMStringMap | null\n): { [key: string]: string } {\n if (!data) {\n return {}\n }\n\n const result: { [key: string]: string } = {}\n for (const key of Object.keys(data)) {\n const value = data[key]\n if (value !== undefined) {\n result[key] = value\n }\n }\n return result\n}\n\n/** Label text only — excludes nested form controls (e.g. wrapped select options). */\nexport function getLabelElementText(label: HTMLLabelElement): string {\n const clone = label.cloneNode(true) as HTMLLabelElement\n clone\n .querySelectorAll('select, option, optgroup, textarea, input, button')\n .forEach((el) => el.remove())\n\n return clone.textContent?.replace(/\\s+/g, ' ').trim() || ''\n}\n\n/** Associated label text for a select, or its aria-label when no label is linked. */\nexport function getAssociatedLabelText(select: HTMLSelectElement): string {\n if (select.labels && select.labels.length > 0) {\n const texts = Array.from(select.labels)\n .map(getLabelElementText)\n .filter(Boolean)\n\n if (texts.length > 0) {\n return [...new Set(texts)].join(' ')\n }\n }\n\n return select.getAttribute('aria-label')?.trim() || ''\n}\n\n// Generate an 8 character random string\nexport function generateID(): string {\n return Math.random().toString(36).substring(2, 10)\n}\n\nexport function hasClassInTree(\n element: HTMLElement,\n className: string\n): HTMLElement | null {\n function hasClass(e: HTMLElement, c: string) {\n // If the element has the class return element\n if (c && e && e.classList && e.classList.contains(c)) {\n return e\n }\n\n // If the element has a dataset id of the class return element\n if (c && e && e.dataset && e.dataset.id && e.dataset.id === className) {\n return e\n }\n\n return null\n }\n\n function parentByClass(e: any, c: string): any {\n if (!e || e === (document as any)) {\n return null\n } else if (hasClass(e, c)) {\n return e\n } else {\n return parentByClass(e.parentNode, c)\n }\n }\n\n return hasClass(element, className) || parentByClass(element, className)\n}\n\n// debounce will call the last requested function after the wait time\nexport function debounce<T extends (...args: any[]) => void>(\n func: T,\n wait = 50,\n immediate = false\n): () => void {\n let timeout: any\n return function (this: any, ...args: any[]): void {\n const context = self\n const later = () => {\n timeout = null\n if (!immediate) {\n func.apply(context, args)\n }\n }\n const callNow = immediate && !timeout\n clearTimeout(timeout)\n timeout = setTimeout(later, wait)\n if (callNow) {\n func.apply(context, args)\n }\n }\n}\n\nexport function isEqual(a: any, b: any): boolean {\n return JSON.stringify(a) === JSON.stringify(b)\n}\n\n/** Compare selected id sets regardless of order (multi-select). */\nexport function selectedIdsEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) {\n return false\n }\n\n const sortedA = [...a].sort()\n const sortedB = [...b].sort()\n return sortedA.every((id, i) => id === sortedB[i])\n}\n\nconst OPTION_FIELDS = [\n 'id',\n 'value',\n 'text',\n 'html',\n 'defaultSelected',\n 'selected',\n 'display',\n 'disabled',\n 'placeholder',\n 'class',\n 'style',\n 'mandatory'\n] as const\n\nfunction shallowRecordEqual(\n a: Record<string, string>,\n b: Record<string, string>\n): boolean {\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n\n if (aKeys.length !== bKeys.length) {\n return false\n }\n\n for (const key of aKeys) {\n if (a[key] !== b[key]) {\n return false\n }\n }\n\n return true\n}\n\nfunction normalizedOptionField(\n option: Partial<Option>,\n field: (typeof OPTION_FIELDS)[number]\n): string | boolean | Record<string, string> {\n switch (field) {\n case 'id':\n return option.id || ''\n case 'value':\n return option.value === undefined ? option.text || '' : option.value || ''\n case 'text':\n return option.text || ''\n case 'html':\n return option.html || ''\n case 'defaultSelected':\n return option.defaultSelected ?? false\n case 'selected':\n return option.selected ?? false\n case 'display':\n return option.display ?? true\n case 'disabled':\n return option.disabled ?? false\n case 'placeholder':\n return option.placeholder ?? false\n case 'class':\n return option.class || ''\n case 'style':\n return option.style || ''\n case 'mandatory':\n return option.mandatory ?? false\n default:\n return option.data || {}\n }\n}\n\nfunction isOptgroupItem(item: DataItem): item is Partial<Optgroup> {\n return (\n !!item && typeof item === 'object' && 'label' in item && 'options' in item\n )\n}\n\nfunction optionStructureEqual(a: Partial<Option>, b: Partial<Option>): boolean {\n for (const field of OPTION_FIELDS) {\n const av = normalizedOptionField(a, field)\n const bv = normalizedOptionField(b, field)\n\n if (av !== bv) {\n return false\n }\n }\n\n return shallowRecordEqual(a.data || {}, b.data || {})\n}\n\nfunction optgroupStructureEqual(\n a: Partial<Optgroup>,\n b: Partial<Optgroup>\n): boolean {\n const normalized = (optgroup: Partial<Optgroup>) => ({\n id: optgroup.id || '',\n label: optgroup.label || '',\n selectAll: optgroup.selectAll ?? false,\n closable: optgroup.closable || 'off'\n })\n\n const aNormalized = normalized(a)\n const bNormalized = normalized(b)\n\n if (\n aNormalized.id !== bNormalized.id ||\n aNormalized.label !== bNormalized.label ||\n aNormalized.selectAll !== bNormalized.selectAll ||\n aNormalized.closable !== bNormalized.closable\n ) {\n return false\n }\n\n const aOptions = a.options || []\n const bOptions = b.options || []\n\n if (aOptions.length !== bOptions.length) {\n return false\n }\n\n for (let i = 0; i < aOptions.length; i++) {\n if (!optionStructureEqual(aOptions[i], bOptions[i])) {\n return false\n }\n }\n\n return true\n}\n\n/** Compare option/optgroup arrays without JSON.stringify. */\nexport function dataStructureEqual(a: DataItem[], b: DataItem[]): boolean {\n if (a === b) {\n return true\n }\n\n if (a.length !== b.length) {\n return false\n }\n\n for (let i = 0; i < a.length; i++) {\n const aItem = a[i]\n const bItem = b[i]\n const aIsOptgroup = isOptgroupItem(aItem)\n const bIsOptgroup = isOptgroupItem(bItem)\n\n if (aIsOptgroup !== bIsOptgroup) {\n return false\n }\n\n if (aIsOptgroup) {\n if (!optgroupStructureEqual(aItem, bItem)) {\n return false\n }\n continue\n }\n\n if (\n !optionStructureEqual(aItem as Partial<Option>, bItem as Partial<Option>)\n ) {\n return false\n }\n }\n\n return true\n}\n\nexport function kebabCase(str: string): string {\n const result = str.replace(\n /[A-Z\\u00C0-\\u00D6\\u00D8-\\u00DE]/g,\n (match) => '-' + match.toLowerCase()\n )\n return str[0] === str[0].toUpperCase() ? result.substring(1) : result\n}\n\nexport function shouldUseModalView(\n modal: ModalSetting,\n viewportWidth: number = typeof window !== 'undefined'\n ? window.innerWidth\n : MODAL_MOBILE_BREAKPOINT\n): boolean {\n if (modal === 'on') {\n return true\n }\n if (modal === 'mobile') {\n return viewportWidth < MODAL_MOBILE_BREAKPOINT\n }\n return false\n}\n","/**\n * Global window/document listeners extracted from SlimSelect.\n *\n * Keeps index.ts thinner and makes listener attach/detach testable in isolation.\n * Document click is separate from attach() so it only runs while dropdown is\n * fully open (wired via Lifecycle onOpenReady / onCloseReady).\n */\n\nimport { debounce, hasClassInTree } from './helpers'\n\nexport interface GlobalEventHandlers {\n onDocumentClick: (e: Event) => void\n onWindowResize: () => void\n onWindowScroll: () => void\n onVisibilityChange: () => void\n}\n\nexport default class GlobalEvents {\n private attached = false\n\n constructor(private handlers: GlobalEventHandlers) {}\n\n /** Attach long-lived listeners for the SlimSelect instance lifetime. */\n public attach(options: { listenScroll: boolean }): void {\n if (this.attached) {\n return\n }\n\n this.attached = true\n window.addEventListener('resize', this.resizeHandler, false)\n\n // Scroll listener only needed when openPosition is auto (reposition on scroll)\n if (options.listenScroll) {\n window.addEventListener('scroll', this.scrollHandler, false)\n }\n\n document.addEventListener('visibilitychange', this.visibilityHandler)\n }\n\n /** Attached after open animation completes — closes on outside click. */\n public attachDocumentClick(): void {\n document.addEventListener('click', this.handlers.onDocumentClick)\n }\n\n public detachDocumentClick(): void {\n document.removeEventListener('click', this.handlers.onDocumentClick)\n }\n\n public detach(options: { listenScroll: boolean }): void {\n if (!this.attached) {\n return\n }\n\n this.attached = false\n this.detachDocumentClick()\n window.removeEventListener('resize', this.resizeHandler, false)\n\n if (options.listenScroll) {\n window.removeEventListener('scroll', this.scrollHandler, false)\n }\n\n document.removeEventListener('visibilitychange', this.visibilityHandler)\n }\n\n private resizeHandler = debounce(() => {\n this.handlers.onWindowResize()\n })\n\n private scrollHandler = debounce(() => {\n this.handlers.onWindowScroll()\n })\n\n private visibilityHandler = () => {\n this.handlers.onVisibilityChange()\n }\n}\n\nexport { hasClassInTree }\n","/**\n * Open/close state machine for SlimSelect.\n *\n * Replaces scattered openTimeout/closeTimeout in index.ts with a single flow:\n * closed → opening → open → closing → closed\n *\n * Maps to settings consumers expect:\n * - isOpen: true during opening + open\n * - isFullOpen: true only in open state (after animation / afterOpen)\n *\n * Lifecycle waits for render.waitForAnimation() before firing afterOpen/afterClose.\n * When no animation waiter is provided, falls back to settings.timeoutDelay.\n *\n * Close flow: beforeClose (veto) → onClose (sync DOM/settings) → animation → afterClose\n */\n\nimport type { CloseInfo } from './render'\n\nexport type LifecycleState = 'closed' | 'opening' | 'open' | 'closing'\n\nexport interface LifecycleHandlers {\n beforeOpen?: () => void\n afterOpen?: () => void\n /** Return false to cancel close before any DOM changes. */\n beforeClose?: (info: CloseInfo) => boolean | void\n /** Sync close work — render, focus, settings. Runs after beforeClose approves. */\n onClose?: (info: CloseInfo) => void\n afterClose?: () => void\n /** Fires when fully open — used to attach document click-outside listener. */\n onOpenReady?: () => void\n /** Fires when fully closed — used to detach document click-outside listener. */\n onCloseReady?: () => void\n}\n\nexport interface LifecycleOptions {\n /** Fallback when waitForAnimation is not provided (no CSS element yet). */\n timeoutDelay: number\n waitForAnimation?: (\n phase: 'open' | 'close',\n signal?: AbortSignal\n ) => Promise<void>\n}\n\nexport default class Lifecycle {\n public state: LifecycleState = 'closed'\n private pendingTimer: ReturnType<typeof setTimeout> | null = null\n /** Resolvers for in-flight waitForPhase promises — cancelled on rapid toggle. */\n private waitResolvers: Array<() => void> = []\n /** Incremented on cancelPending(); stale async completions check this before firing handlers. */\n private generation = 0\n private animationAbort: AbortController | null = null\n\n constructor(\n private handlers: LifecycleHandlers,\n private options: LifecycleOptions\n ) {}\n\n public get isOpen(): boolean {\n return this.state === 'opening' || this.state === 'open'\n }\n\n public get isFullOpen(): boolean {\n return this.state === 'open'\n }\n\n public async requestOpen(): Promise<void> {\n if (this.state === 'opening' || this.state === 'open') {\n return\n }\n\n this.cancelPending()\n const gen = ++this.generation\n\n if (this.handlers.beforeOpen) {\n this.handlers.beforeOpen()\n }\n\n this.state = 'opening'\n await this.waitForPhase('open', gen)\n\n // User closed before open animation finished (issue #397)\n if (gen !== this.generation) {\n if (this.state === 'opening') {\n this.state = 'closed'\n }\n return\n }\n\n this.state = 'open'\n\n if (this.handlers.afterOpen) {\n this.handlers.afterOpen()\n }\n\n if (this.handlers.onOpenReady) {\n this.handlers.onOpenReady()\n }\n }\n\n public async requestClose(\n info: CloseInfo = { source: 'api', selectionChanged: false }\n ): Promise<boolean> {\n if (this.state === 'closed' || this.state === 'closing') {\n return false\n }\n\n if (this.handlers.beforeClose && this.handlers.beforeClose(info) === false) {\n return false\n }\n\n this.cancelPending()\n const gen = ++this.generation\n\n if (this.handlers.onClose) {\n this.handlers.onClose(info)\n }\n\n this.state = 'closing'\n await this.waitForPhase('close', gen)\n\n if (gen !== this.generation) {\n return false\n }\n\n this.state = 'closed'\n\n if (this.handlers.afterClose) {\n this.handlers.afterClose()\n }\n\n if (this.handlers.onCloseReady) {\n this.handlers.onCloseReady()\n }\n\n return true\n }\n\n /** Cancel timers and resolve waiting phases — called when open/close race each other. */\n public cancelPending(): void {\n this.generation++\n this.animationAbort?.abort()\n this.animationAbort = null\n if (this.pendingTimer) {\n clearTimeout(this.pendingTimer)\n this.pendingTimer = null\n }\n const resolvers = this.waitResolvers.splice(0)\n for (const resolve of resolvers) {\n resolve()\n }\n }\n\n public destroy(): void {\n this.cancelPending()\n this.state = 'closed'\n }\n\n /**\n * Wait for the CSS animation to finish (or timeoutDelay when no waiter exists).\n * cancelPending() resolves the wait early for rapid open/close toggles.\n */\n private waitForPhase(\n phase: 'open' | 'close',\n gen: number\n ): Promise<void> {\n return new Promise<void>((resolve) => {\n let settled = false\n const finish = () => {\n if (settled) {\n return\n }\n settled = true\n const idx = this.waitResolvers.indexOf(finish)\n if (idx !== -1) {\n this.waitResolvers.splice(idx, 1)\n }\n resolve()\n }\n\n this.waitResolvers.push(finish)\n\n if (this.options.waitForAnimation) {\n const controller = new AbortController()\n this.animationAbort = controller\n void this.options\n .waitForAnimation(phase, controller.signal)\n .catch(() => undefined)\n .finally(() => {\n if (this.animationAbort === controller) {\n this.animationAbort = null\n }\n finish()\n })\n } else {\n this.pendingTimer = setTimeout(() => {\n this.pendingTimer = null\n finish()\n }, this.options.timeoutDelay)\n }\n }).then(() => {\n if (gen !== this.generation) {\n return\n }\n })\n }\n}\n","import { copyOptionData, generateID } from './helpers'\n\nexport class Option {\n id: string\n value: string\n text: string\n html: string\n defaultSelected: boolean\n selected: boolean\n display: boolean\n disabled: boolean\n placeholder: boolean\n class: string\n style: string\n data: { [key: string]: string }\n mandatory: boolean\n\n constructor(option: Partial<Option>) {\n this.id = !option.id || option.id === '' ? generateID() : option.id\n this.value =\n option.value === undefined ? option.text || '' : option.value || ''\n this.text = option.text || ''\n this.html = option.html || ''\n this.defaultSelected =\n option.defaultSelected !== undefined ? option.defaultSelected : false\n this.selected = option.selected !== undefined ? option.selected : false\n this.display = option.display !== undefined ? option.display : true\n this.disabled = option.disabled !== undefined ? option.disabled : false\n this.mandatory = option.mandatory !== undefined ? option.mandatory : false\n this.placeholder =\n option.placeholder !== undefined ? option.placeholder : false\n this.class = option.class || ''\n this.style = option.style || ''\n this.data = copyOptionData(option.data)\n }\n}\nexport class Optgroup {\n public id: string\n public label: string\n public selectAll: boolean\n public closable: 'off' | 'open' | 'close'\n public options: Partial<Option>[]\n\n constructor(optgroup: Partial<Optgroup>) {\n this.id = !optgroup.id || optgroup.id === '' ? generateID() : optgroup.id\n this.label = optgroup.label || ''\n this.selectAll =\n optgroup.selectAll === undefined ? false : optgroup.selectAll\n this.closable = optgroup.closable || 'off'\n\n // If options exist, loop through options and create new option class\n // and set the options to the optgroup options field\n this.options = []\n if (optgroup.options) {\n for (const o of optgroup.options) {\n this.options.push(new Option(o))\n }\n }\n }\n}\n\nexport default class Store {\n private selectType: 'single' | 'multiple' = 'single'\n\n // Main data set, never null\n private data: (Option | Optgroup)[] = []\n private selectedOrder: string[] = []\n /** Baseline option list — restored when search is cleared (API results are temporary). */\n private catalog: (Option | Optgroup)[] | null = null\n\n constructor(\n type: 'single' | 'multiple',\n data: (Partial<Option> | Partial<Optgroup>)[]\n ) {\n this.selectType = type\n this.setData(data)\n this.snapshotCatalog()\n }\n\n // Validate DataArrayPartial\n public validateDataArray(\n data: (Partial<Option> | Partial<Optgroup>)[]\n ): Error | null {\n if (!Array.isArray(data)) {\n return new Error('Data must be an array')\n }\n\n // Loop through each data object\n for (let dataObj of data) {\n if (!dataObj) continue\n\n // Optgroup\n if (dataObj instanceof Optgroup || 'label' in dataObj) {\n if (!('label' in dataObj)) {\n return new Error('Optgroup must have a label')\n }\n\n if ('options' in dataObj && dataObj.options) {\n for (let option of dataObj.options) {\n const validationError = this.validateOption(option)\n if (validationError) {\n return validationError\n }\n }\n }\n } else if (dataObj instanceof Option || 'text' in dataObj) {\n const validationError = this.validateOption(dataObj)\n if (validationError) {\n return validationError\n }\n } else {\n return new Error('Data object must be a valid optgroup or option')\n }\n }\n\n return null\n }\n\n // Validate Option\n public validateOption(option: Partial<Option>): Error | null {\n if (!('text' in option)) {\n return new Error('Option must have a text')\n }\n\n return null\n }\n\n public partialToFullData(\n data: (Partial<Option> | Partial<Optgroup>)[]\n ): (Option | Optgroup)[] {\n let dataFinal: (Option | Optgroup)[] = []\n data.forEach((dataObj) => {\n if (!dataObj) return\n\n // Optgroup\n if (dataObj instanceof Optgroup || 'label' in dataObj) {\n let optOptions: Option[] = []\n if ('options' in dataObj && dataObj.options) {\n dataObj.options.forEach((option: Partial<Option>) => {\n optOptions.push(new Option(option))\n })\n }\n\n if (optOptions.length > 0) {\n dataFinal.push(new Optgroup(dataObj as Partial<Optgroup>))\n }\n }\n\n // Option\n if (dataObj instanceof Option || 'text' in dataObj) {\n dataFinal.push(new Option(dataObj as Partial<Option>))\n }\n })\n\n return dataFinal\n }\n\n /** Snapshot the current data as the catalog baseline (not called for API search results). */\n public snapshotCatalog(): void {\n this.catalog = this.cloneData(this.data)\n }\n\n /** Catalog baseline used when clearing search. */\n public getCatalogData(): (Option | Optgroup)[] {\n return this.cloneData(this.catalog ?? this.data)\n }\n\n private cloneData(data: (Option | Optgroup)[]): (Option | Optgroup)[] {\n return data.map((item) => {\n if (item instanceof Optgroup) {\n return new Optgroup({\n id: item.id,\n label: item.label,\n selectAll: item.selectAll,\n closable: item.closable,\n options: item.options.map((option) =>\n new Option(option instanceof Option ? { ...option } : option)\n )\n })\n }\n\n return new Option({ ...(item as Option) })\n })\n }\n\n private optionMatchesSelected(\n candidate: Option,\n selected: Option\n ): boolean {\n if (candidate.id === selected.id) {\n return true\n }\n\n return (\n selected.value !== '' &&\n candidate.value !== '' &&\n candidate.value === selected.value\n )\n }\n\n private findOptionInData(\n data: (Option | Optgroup)[],\n selected: Option\n ): Option | null {\n for (const item of data) {\n if (item instanceof Option) {\n if (this.optionMatchesSelected(item, selected)) {\n return item\n }\n continue\n }\n\n for (const option of item.options as Option[]) {\n if (this.optionMatchesSelected(option, selected)) {\n return option\n }\n }\n }\n\n return null\n }\n\n public setData(\n data: (Partial<Option> | Partial<Optgroup>)[],\n preserveSelected: boolean = false\n ) {\n // Convert new data to full data array\n const newData = this.partialToFullData(data)\n\n let selectedOptionsBeforeUpdate: Option[] = []\n\n if (preserveSelected) {\n // Get currently selected options before updating data\n selectedOptionsBeforeUpdate = this.getSelectedOptions()\n\n // Check which selected options are missing from new data\n const missingSelected: Option[] = []\n selectedOptionsBeforeUpdate.forEach((selectedOption) => {\n if (!this.findOptionInData(newData, selectedOption)) {\n missingSelected.push(selectedOption)\n }\n })\n\n // Add missing selected options to the beginning of the data\n this.data = [...missingSelected, ...newData]\n\n const allowEmptySelection =\n this.selectType === 'single' &&\n selectedOptionsBeforeUpdate.length === 0\n const selectedIds = selectedOptionsBeforeUpdate.map((selected) => {\n const match = this.findOptionInData(this.data, selected)\n return match ? match.id : selected.id\n })\n\n this.setSelectedBy('id', selectedIds, allowEmptySelection)\n } else {\n this.data = newData\n }\n\n // Run this.data through setSelected by value\n // to set the selected property and clean any wrong selected\n if (!preserveSelected && this.selectType === 'single') {\n this.setSelectedBy('id', this.getSelected(), false)\n }\n }\n\n // Get data will return all the data (cloned by default for public API safety)\n public getData(clone = true): Option[] | Optgroup[] {\n return this.filter(null, true, clone) as Option[] | Optgroup[]\n }\n\n // Get data options will return the data as a flat array of just options\n public getDataOptions(clone = true): Option[] {\n return this.filter(null, false, clone) as Option[]\n }\n\n public addOption(option: Partial<Option>, addToStart: boolean = false) {\n if (addToStart) {\n let data = [new Option(option)] as (Option | Optgroup)[]\n this.setData(data.concat(this.getData()))\n } else {\n this.setData(this.getData().concat(new Option(option)))\n }\n }\n\n // Pass in an array of id that will loop through\n // each option and set the selected property to true\n // but also clean selected by determining selectType\n // When allowEmptySelection is true (e.g. after search with no prior selection), single select will not auto-select the first option\n public setSelectedBy(\n selectedType: 'id' | 'value',\n selectedValues: string[],\n allowEmptySelection: boolean = false\n ) {\n let firstOption: Partial<Option> | null = null\n let hasSelected = false\n const selectedObjects: Partial<Option>[] = []\n\n for (let dataObj of this.data) {\n // Optgroup\n if (dataObj instanceof Optgroup) {\n for (let option of dataObj.options as Partial<Option>[]) {\n if (!firstOption) {\n firstOption = option\n }\n\n let optionValue = option[selectedType] || ''\n option.selected = hasSelected\n ? false\n : selectedValues.includes(optionValue)\n\n // If the option is selected, set hasSelected to true\n // for single based selects\n if (option.selected) {\n selectedObjects.push(option)\n\n if (this.selectType === 'single') {\n hasSelected = true\n }\n }\n }\n }\n\n // Option\n if (dataObj instanceof Option) {\n if (!firstOption) {\n firstOption = dataObj\n }\n\n dataObj.selected = hasSelected\n ? false\n : selectedValues.includes(dataObj[selectedType])\n\n // If the option is selected, set hasSelected to true\n // for single based selects\n if (dataObj.selected) {\n selectedObjects.push(dataObj)\n\n if (this.selectType === 'single') {\n hasSelected = true\n }\n }\n }\n }\n\n // If no options are selected, select the first option (unless allowEmptySelection, e.g. after search with no selection)\n if (\n this.selectType === 'single' &&\n firstOption &&\n !hasSelected &&\n !allowEmptySelection\n ) {\n firstOption.selected = true\n selectedObjects.push(firstOption)\n }\n\n // Put together a list of selected ids in the order of the selected values\n const selectedIds = selectedValues.map((value) => {\n return (\n selectedObjects.find((option) => option[selectedType] === value)?.id ||\n ''\n )\n })\n\n this.selectedOrder = selectedIds\n }\n\n public getSelected(): string[] {\n return this.getSelectedOptions().map((option) => option.id)\n }\n\n public getSelectedValues(): string[] {\n return this.getSelectedOptions().map((option) => option.value)\n }\n\n public getSelectedOptions(): Option[] {\n const selected: Option[] = []\n\n for (const dataObj of this.data) {\n if (dataObj instanceof Optgroup) {\n for (const option of dataObj.options as Option[]) {\n if (option.selected) {\n selected.push(option)\n }\n }\n } else if (dataObj.selected) {\n selected.push(dataObj)\n }\n }\n\n return selected\n }\n\n public getOptgroupByID(id: string): Optgroup | null {\n // Loop through each data object\n // and if optgroup is found, return it\n for (let dataObj of this.data) {\n if (dataObj instanceof Optgroup && dataObj.id === id) {\n return dataObj\n }\n }\n\n return null\n }\n\n public getOptionByID(id: string): Option | null {\n for (const dataObj of this.data) {\n if (dataObj instanceof Optgroup) {\n for (const option of dataObj.options as Option[]) {\n if (option.id === id) {\n return option\n }\n }\n } else if (dataObj.id === id) {\n return dataObj\n }\n }\n\n return null\n }\n\n public getSelectType(): string {\n return this.selectType\n }\n\n public getFirstOption(): Option | null {\n let option: Option | null = null\n for (let dataObj of this.data) {\n if (dataObj instanceof Optgroup) {\n option = dataObj.options[0] as Option\n } else if (dataObj instanceof Option) {\n option = dataObj\n }\n\n if (option) {\n break\n }\n }\n return option\n }\n\n // Take in search string and return filtered list of values\n public search(\n search: string,\n searchFilter: (opt: Option, search: string) => boolean\n ): (Option | Optgroup)[] {\n search = search.trim()\n\n // If search is empty, return all data\n if (search === '') {\n return this.getData(false)\n }\n\n // Run filter with search function (read-only view for render)\n return this.filter((opt: Option): boolean => {\n return searchFilter(opt, search)\n }, true, false)\n }\n\n private createOptgroupView(\n source: Optgroup,\n options: Option[]\n ): Optgroup {\n const view = new Optgroup({\n id: source.id,\n label: source.label,\n selectAll: source.selectAll,\n closable: source.closable,\n options: []\n })\n view.options = options\n return view\n }\n\n // Filter takes in a function that will be used to filter the data\n // This will also keep optgroups of sub options meet the filter requirements\n public filter(\n filter: { (opt: Option): boolean } | null,\n includeOptgroup: boolean,\n clone = true\n ): (Option | Optgroup)[] {\n const dataSearch: (Option | Optgroup)[] = []\n this.data.forEach((dataObj: Option | Optgroup) => {\n // Optgroup\n if (dataObj instanceof Optgroup) {\n let optOptions: Option[] = []\n let options = dataObj.options as Option[]\n options.forEach((option: Option) => {\n if (!filter || filter(option as Option)) {\n // If you dont want to include optgroups\n // just push to the dataSearch array\n if (!includeOptgroup) {\n dataSearch.push(clone ? new Option(option) : option)\n } else {\n optOptions.push(clone ? new Option(option) : option)\n }\n }\n })\n\n // If we pushed any options to the optOptions array\n // push the optgroup to the dataSearch array\n if (optOptions.length > 0) {\n if (clone) {\n let optgroup = new Optgroup(dataObj)\n optgroup.options = optOptions\n dataSearch.push(optgroup)\n } else {\n dataSearch.push(this.createOptgroupView(dataObj, optOptions))\n }\n }\n }\n\n // Option\n if (dataObj instanceof Option) {\n if (!filter || filter(dataObj)) {\n dataSearch.push(clone ? new Option(dataObj) : dataObj)\n }\n }\n })\n\n return dataSearch\n }\n\n // Take in an array of options and reoder them based upon the selected order\n public selectedOrderOptions(options: Option[]): Option[] {\n const newOrder: Option[] = []\n this.selectedOrder.forEach((id) => {\n const option = options.find((opt) => opt.id === id)\n if (option) {\n newOrder.push(option)\n }\n })\n\n // add any remaining options that were not in the selected order\n options.forEach((option) => {\n let isIn = false\n newOrder.forEach((selectedOption) => {\n if (option.id === selectedOption.id) {\n isIn = true\n\n return\n }\n })\n\n if (!isIn) {\n newOrder.push(option)\n }\n })\n\n return newOrder\n }\n}\n","import { debounce, shouldUseModalView } from './helpers'\nimport {\n CONTENT_PANEL_TRANSITION_PROPERTIES,\n getAnimationDuration,\n getAnimationTimeout,\n waitForAnimationEnd,\n waitForTransitionEnd\n} from './animations'\nimport Settings from './settings'\nimport Store, { Optgroup, Option } from './store'\nimport CssClasses from './classes'\n\nexport type CloseSource =\n | 'select'\n | 'deselect'\n | 'outside'\n | 'toggle'\n | 'escape'\n | 'tab'\n | 'modal'\n | 'api'\n\nexport interface CloseInfo {\n source: CloseSource\n option?: Option\n selectionChanged: boolean\n}\n\nexport interface Callbacks {\n open: () => void\n close: (info?: CloseInfo) => void\n addable?: (\n value: string\n ) =>\n | Promise<Partial<Option> | string>\n | Partial<Option>\n | string\n | false\n | undefined\n | null\n | Error\n setSelected: (value: string | string[], runAfterChange: boolean) => void\n addOption: (option: Option) => void\n search: (search: string) => void\n beforeChange?: (newVal: Option[], oldVal: Option[]) => boolean | void\n afterChange?: (newVal: Option[]) => void\n}\n\nexport interface Main {\n main: HTMLDivElement\n values: HTMLDivElement\n deselect: {\n main: HTMLDivElement\n svg: SVGSVGElement\n path: SVGPathElement\n }\n arrow: {\n main: SVGSVGElement\n path: SVGPathElement\n }\n}\n\nexport interface Content {\n main: HTMLDivElement\n search: Search\n status: HTMLDivElement\n list: HTMLDivElement\n}\n\nexport interface Search {\n main: HTMLDivElement\n input: HTMLInputElement\n addable?: {\n main: HTMLDivElement\n svg: SVGSVGElement\n path: SVGPathElement\n }\n}\n\nexport interface ModalElements {\n overlay: HTMLDivElement\n dialog: HTMLDivElement\n closeButton: HTMLButtonElement\n title: HTMLDivElement | null\n}\n\nexport default class Render {\n public settings: Settings\n public store: Store\n public callbacks: Callbacks\n\n // Used to compute the range selection\n private lastSelectedOption: Option | null\n private lastRenderedOptions: Option[]\n private optionsListIsFullData = false\n private lastSearchFilterTerm = ''\n\n // Timeout tracking for cleanup\n\n // Elements\n public main: Main\n public content: Content\n\n // Classes\n public classes: CssClasses\n\n private positionObserver: ResizeObserver | null = null\n private positionObserverRaf = 0\n private overflowShiftRaf = 0\n\n private modalElements: ModalElements | null = null\n private modalSessionActive: boolean | null = null\n private bodyScrollLocked = false\n private savedBodyOverflow = ''\n\n constructor(\n settings: Required<Settings>,\n classes: Required<CssClasses>,\n store: Store,\n callbacks: Callbacks\n ) {\n this.store = store\n this.settings = settings\n this.classes = classes\n this.callbacks = callbacks\n this.lastSelectedOption = null\n this.lastRenderedOptions = []\n\n this.main = this.mainDiv()\n this.content = this.contentDiv()\n\n // Add classes and styles to main/content\n this.updateClassStyles()\n this.updateAriaAttributes()\n\n // Position content off-screen initially to prevent scrollbars\n // This must be after updateClassStyles() since it removes all style attributes\n // The main element isn't in the DOM yet, so getBoundingClientRect() would return zeros\n // Once opened, moveContent() will position it correctly\n if (this.settings.contentPosition !== 'relative') {\n this.content.main.style.top = '-9999px'\n this.content.main.style.left = '-9999px'\n this.content.main.style.margin = '0'\n this.content.main.style.width = 'auto'\n }\n\n // Add content to the content location settings\n if (this.settings.contentLocation) {\n this.settings.contentLocation.appendChild(this.content.main)\n }\n\n if (this.settings.modal !== 'off' && !this.settings.alwaysOpen) {\n this.modalElements = this.createModalElements()\n document.body.appendChild(this.modalElements.overlay)\n }\n }\n\n // Helper method to add classes that may contain spaces\n // Splits by spaces and adds each class individually to avoid DOMException\n private requestClose(\n source: CloseSource,\n options?: { option?: Option; selectionChanged?: boolean }\n ): void {\n this.callbacks.close({\n source,\n option: options?.option,\n selectionChanged: options?.selectionChanged ?? false\n })\n }\n\n private selectionChanged(before: Option[], after: Option[]): boolean {\n if (before.length !== after.length) {\n return true\n }\n\n const beforeIds = before.map((o) => o.id).sort()\n const afterIds = after.map((o) => o.id).sort()\n\n return beforeIds.some((id, index) => id !== afterIds[index])\n }\n\n private closeOnSingleSelectReclick(storeOption: Option): void {\n if (this.settings.closeOnSelect) {\n this.requestClose('select', {\n option: storeOption,\n selectionChanged: false\n })\n }\n }\n\n public addClasses(\n element: HTMLElement | SVGElement,\n classValue: string\n ): void {\n if (!classValue || classValue.trim() === '') {\n return\n }\n const classes = classValue.split(' ').filter((c) => c.trim() !== '')\n for (const cls of classes) {\n element.classList.add(cls.trim())\n }\n }\n\n // Helper method to remove classes that may contain spaces\n public removeClasses(\n element: HTMLElement | SVGElement,\n classValue: string\n ): void {\n if (!classValue || classValue.trim() === '') {\n return\n }\n const classes = classValue.split(' ').filter((c) => c.trim() !== '')\n for (const cls of classes) {\n element.classList.remove(cls.trim())\n }\n }\n\n // Remove disabled classes\n public enable(): void {\n // Remove disabled class\n this.removeClasses(this.main.main, this.classes.disabled)\n this.main.main.setAttribute('aria-disabled', 'false')\n\n // Set search input to \"enabled\"\n this.content.search.input.disabled = false\n }\n\n // Set disabled classes\n public disable(): void {\n // Add disabled class\n this.addClasses(this.main.main, this.classes.disabled)\n this.main.main.setAttribute('aria-disabled', 'true')\n\n // Set search input to disabled\n this.content.search.input.disabled = true\n }\n\n public open(): void {\n this.main.arrow.path.setAttribute('d', this.classes.arrowOpen)\n this.main.main.setAttribute('aria-expanded', 'true')\n\n const useModal = this.resolveModalView()\n\n if (!useModal) {\n const isAbove = this.settings.openPosition === 'up'\n const dirClass = isAbove ? this.classes.dirAbove : this.classes.dirBelow\n this.addClasses(this.main.main, dirClass)\n this.addClasses(this.content.main, dirClass)\n }\n\n // Add open class to content to trigger open animation\n this.addClasses(this.content.main, this.classes.contentOpen)\n\n // Make search visible to screen readers when opened\n this.content.search.input.removeAttribute('aria-hidden')\n\n if (useModal) {\n this.showModal()\n } else {\n this.moveContent()\n }\n\n // Move to last selected option\n const selectedOptions = this.store.getSelectedOptions()\n if (selectedOptions.length) {\n const selectedId = selectedOptions[selectedOptions.length - 1].id\n const selectedOption = this.content.list.querySelector(\n '[data-id=\"' + selectedId + '\"]'\n ) as HTMLElement\n if (selectedOption) {\n this.ensureElementInView(this.content.list, selectedOption)\n }\n }\n }\n\n public isModalViewActive(): boolean {\n return this.modalSessionActive === true\n }\n\n private resolveModalView(): boolean {\n if (\n this.settings.alwaysOpen ||\n this.settings.modal === 'off' ||\n !this.modalElements\n ) {\n return false\n }\n\n if (this.modalSessionActive === null) {\n this.modalSessionActive = shouldUseModalView(this.settings.modal)\n }\n\n return this.modalSessionActive\n }\n\n private createModalElements(): ModalElements {\n const overlay = document.createElement('div')\n this.addClasses(overlay, this.classes.modalOverlay)\n this.addClasses(overlay, this.classes.hide)\n overlay.dataset.id = this.settings.id\n\n const dialog = document.createElement('div')\n this.addClasses(dialog, this.classes.modalDialog)\n dialog.setAttribute('role', 'dialog')\n dialog.setAttribute('aria-modal', 'true')\n\n let title: HTMLDivElement | null = null\n if (this.settings.modalTitle) {\n title = document.createElement('div')\n this.addClasses(title, this.classes.modalTitle)\n title.id = `${this.settings.id}-modal-title`\n title.textContent = this.settings.modalTitle\n dialog.setAttribute('aria-labelledby', title.id)\n } else {\n dialog.setAttribute('aria-label', this.settings.ariaLabel)\n }\n\n const closeButton = document.createElement('button')\n closeButton.type = 'button'\n this.addClasses(closeButton, this.classes.modalClose)\n closeButton.setAttribute('aria-label', 'Close')\n closeButton.onclick = (e: Event) => {\n e.stopPropagation()\n this.requestClose('modal')\n }\n\n const closeSvg = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'svg'\n )\n closeSvg.setAttribute('viewBox', '0 0 100 100')\n const closePath = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n closePath.setAttribute('d', this.classes.deselectPath)\n closeSvg.appendChild(closePath)\n closeButton.appendChild(closeSvg)\n\n overlay.onclick = (e: Event) => {\n if (e.target === overlay) {\n this.requestClose('modal')\n }\n }\n\n if (title) {\n dialog.appendChild(title)\n }\n overlay.appendChild(dialog)\n\n return { overlay, dialog, closeButton, title }\n }\n\n private showModal(): void {\n if (!this.modalElements) {\n return\n }\n\n this.modalElements.dialog.appendChild(this.content.main)\n this.addClasses(this.content.main, this.classes.modalContent)\n this.content.main.appendChild(this.modalElements.closeButton)\n this.content.main.style.top = ''\n this.content.main.style.left = ''\n this.content.main.style.margin = ''\n this.content.main.style.width = ''\n\n this.removeClasses(this.modalElements.overlay, this.classes.hide)\n requestAnimationFrame(() => {\n if (!this.modalElements) {\n return\n }\n this.addClasses(this.modalElements.overlay, this.classes.contentOpen)\n })\n\n this.lockBodyScroll()\n }\n\n private lockBodyScroll(): void {\n if (this.bodyScrollLocked) {\n return\n }\n\n this.savedBodyOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n this.bodyScrollLocked = true\n }\n\n private unlockBodyScroll(): void {\n if (!this.bodyScrollLocked) {\n return\n }\n\n document.body.style.overflow = this.savedBodyOverflow\n this.bodyScrollLocked = false\n this.savedBodyOverflow = ''\n }\n\n private restoreContentOffscreen(): void {\n if (this.settings.contentLocation) {\n this.settings.contentLocation.appendChild(this.content.main)\n }\n\n if (this.settings.contentPosition !== 'relative') {\n this.content.main.style.top = '-9999px'\n this.content.main.style.left = '-9999px'\n this.content.main.style.margin = '0'\n this.content.main.style.width = 'auto'\n }\n }\n\n /** Tear down modal shell after close animation completes. */\n public finalizeModalClose(): void {\n if (!this.modalElements) {\n return\n }\n\n if (this.content.main.parentElement !== this.modalElements.dialog) {\n return\n }\n\n this.addClasses(this.modalElements.overlay, this.classes.hide)\n this.removeClasses(this.modalElements.overlay, this.classes.contentOpen)\n this.removeClasses(this.content.main, this.classes.modalContent)\n this.modalElements.closeButton.remove()\n this.restoreContentOffscreen()\n this.unlockBodyScroll()\n }\n\n /** Used by Lifecycle — wait for .ss-content CSS transition before afterOpen/afterClose. */\n public waitForAnimation(\n phase: 'open' | 'close',\n signal?: AbortSignal\n ): Promise<void> {\n const timeout = getAnimationTimeout(\n this.content.main,\n this.settings.timeoutDelay\n )\n return waitForTransitionEnd(\n this.content.main,\n CONTENT_PANEL_TRANSITION_PROPERTIES,\n timeout,\n signal\n )\n }\n\n public close(): void {\n this.main.main.setAttribute('aria-expanded', 'false')\n this.main.arrow.path.setAttribute('d', this.classes.arrowClose)\n\n const wasModal = this.modalSessionActive === true\n\n // Remove open class from content to trigger close animation\n // Direction on content persists for transform-origin during the panel animation\n this.removeClasses(this.content.main, this.classes.contentOpen)\n\n if (!wasModal) {\n this.removeClasses(this.main.main, this.classes.dirAbove)\n this.removeClasses(this.main.main, this.classes.dirBelow)\n }\n\n if (wasModal && this.modalElements) {\n this.removeClasses(this.modalElements.overlay, this.classes.contentOpen)\n }\n\n this.modalSessionActive = null\n\n // Hide search from screen readers when closed\n this.content.search.input.setAttribute('aria-hidden', 'true')\n\n // Clear active descendant when closed\n this.main.main.removeAttribute('aria-activedescendant')\n }\n\n /** Remove open-direction classes after close animation (lifecycle afterClose). */\n public clearDirectionClasses(): void {\n this.removeClasses(this.main.main, this.classes.dirAbove)\n this.removeClasses(this.main.main, this.classes.dirBelow)\n this.removeClasses(this.content.main, this.classes.dirAbove)\n this.removeClasses(this.content.main, this.classes.dirBelow)\n }\n\n public updateClassStyles(): void {\n // Clear all classes and styles\n this.main.main.className = ''\n this.main.main.removeAttribute('style')\n this.content.main.className = ''\n this.content.main.removeAttribute('style')\n\n // Make sure main/content has its base class\n this.addClasses(this.main.main, this.classes.main)\n this.addClasses(this.content.main, this.classes.content)\n\n // Add styles\n if (this.settings.style !== '') {\n this.main.main.style.cssText = this.settings.style\n this.content.main.style.cssText = this.settings.style\n }\n\n // Add classes from the native select to both main and content\n if (this.settings.class.length) {\n for (const c of this.settings.class) {\n if (c.trim() !== '') {\n this.main.main.classList.add(c.trim())\n this.content.main.classList.add(c.trim())\n }\n }\n }\n\n // Misc classes\n // Add content position class\n if (\n this.settings.contentPosition === 'relative' ||\n this.settings.contentPosition === 'fixed'\n ) {\n this.content.main.classList.add('ss-' + this.settings.contentPosition)\n }\n }\n\n public updateAriaAttributes() {\n const listboxId = this.content.list.id\n\n // Main combobox\n this.main.main.role = 'combobox'\n this.main.main.setAttribute('aria-haspopup', 'listbox')\n this.main.main.setAttribute('aria-controls', listboxId)\n this.main.main.setAttribute('aria-expanded', 'false')\n\n this.content.list.setAttribute('role', 'listbox')\n this.content.list.setAttribute(\n 'aria-label',\n this.settings.ariaLabel + ' listbox'\n )\n\n // Add aria-multiselectable for multiple selects\n if (this.settings.isMultiple) {\n this.content.list.setAttribute('aria-multiselectable', 'true')\n }\n\n // Search input should also control the listbox\n this.content.search.input.setAttribute('aria-controls', listboxId)\n }\n\n public mainDiv(): Main {\n // Create main container\n const main = document.createElement('div')\n\n // Add id to data-id\n main.dataset.id = this.settings.id\n // main.id = this.settings.id+'-main' // Remove for now as it is not needed and add duplicate id errors\n\n // Add label\n main.setAttribute('aria-label', this.settings.ariaLabel)\n\n // Set tabable to allow tabbing to the element\n main.tabIndex = 0\n\n // Deal with keyboard events on the main div\n // This is to allow for normal selecting\n // when you may not have a search bar\n main.onkeydown = (e: KeyboardEvent): boolean => {\n // Convert above if else statemets to switch\n switch (e.key) {\n case 'ArrowUp':\n case 'ArrowDown':\n this.callbacks.open()\n e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up')\n return false\n case 'Tab':\n this.requestClose('tab')\n return true // Continue doing normal tabbing\n case 'Enter':\n case ' ':\n this.callbacks.open()\n const highlighted = this.content.list.querySelector(\n '.' + this.classes.getFirst('highlighted')\n ) as HTMLDivElement\n if (highlighted) {\n highlighted.click()\n }\n return false\n case 'Escape':\n this.requestClose('escape')\n return false\n }\n\n // Check if they type a-z, A-Z and 0-9\n if (e.key.length === 1) {\n this.callbacks.open()\n }\n\n return true\n }\n\n // Add onclick for main div\n main.onclick = (e: Event): void => {\n // Dont do anything if disabled\n if (this.settings.disabled) {\n return\n }\n\n this.settings.isOpen\n ? this.requestClose('toggle')\n : this.callbacks.open()\n }\n\n // Add values\n const values = document.createElement('div')\n this.addClasses(values, this.classes.values)\n main.appendChild(values)\n\n // Add deselect\n const deselect = document.createElement('div')\n this.addClasses(deselect, this.classes.deselect)\n deselect.setAttribute('role', 'button')\n deselect.setAttribute('aria-label', this.settings.deselectText)\n deselect.setAttribute('tabindex', '0')\n\n // Check if deselect is to be shown or not\n const selectedOptions = this.store?.getSelectedOptions()\n if (\n !this.settings.allowDeselect ||\n (this.settings.isMultiple &&\n selectedOptions &&\n selectedOptions.length <= 0) ||\n this.isAtMinSelected()\n ) {\n this.addClasses(deselect, this.classes.hide)\n } else {\n this.removeClasses(deselect, this.classes.hide)\n }\n\n // Add deselect onclick event\n deselect.onclick = (e: Event) => {\n e.stopPropagation()\n\n // Dont do anything if disabled\n if (this.settings.disabled) {\n return\n }\n\n if (this.settings.isMultiple && this.isAtMinSelected()) {\n return\n }\n\n // By Default we will delete\n let shouldDelete = true\n const before = this.store.getSelectedOptions()\n let after = [] as Option[]\n let newSelectedIds: string[] | string = ''\n\n if (this.settings.isMultiple) {\n const min = this.settings.minSelected\n const currentIds = this.store.getSelected()\n\n if (min > 0 && currentIds.length > min) {\n newSelectedIds = this.getMinimumSelectionIds()\n after = before.filter((o) => newSelectedIds.includes(o.id))\n } else if (min <= 0) {\n newSelectedIds = []\n } else {\n return\n }\n }\n\n // Add beforeChange callback\n if (this.callbacks.beforeChange) {\n shouldDelete = this.callbacks.beforeChange(after, before) === true\n }\n\n if (shouldDelete) {\n if (this.settings.isMultiple) {\n this.callbacks.setSelected(newSelectedIds, false)\n this.updateDeselectAll()\n } else {\n // Get first option and set it as selected\n const firstOption = this.store.getFirstOption()\n const id = firstOption ? firstOption.id : ''\n\n this.callbacks.setSelected(id, false)\n }\n\n // Check if we need to close the dropdown\n if (this.settings.closeOnSelect) {\n this.requestClose('deselect', { selectionChanged: true })\n }\n\n // Run afterChange callback\n if (this.callbacks.afterChange) {\n this.callbacks.afterChange(this.store.getSelectedOptions())\n }\n }\n }\n\n deselect.onkeydown = (e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n deselect.click()\n }\n }\n\n // Add deselect svg\n const deselectSvg = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'svg'\n )\n deselectSvg.setAttribute('viewBox', '0 0 100 100')\n const deselectPath = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n deselectPath.setAttribute('d', this.classes.deselectPath)\n deselectSvg.appendChild(deselectPath)\n deselect.appendChild(deselectSvg)\n main.appendChild(deselect)\n\n // Add arrow\n const arrow = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n this.addClasses(arrow, this.classes.arrow)\n arrow.setAttribute('viewBox', '0 0 100 100')\n const arrowPath = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n arrowPath.setAttribute('d', this.classes.arrowClose)\n if (this.settings.alwaysOpen) {\n this.addClasses(arrow, this.classes.hide)\n }\n arrow.appendChild(arrowPath)\n main.appendChild(arrow)\n\n return {\n main: main,\n values: values,\n deselect: {\n main: deselect,\n svg: deselectSvg,\n path: deselectPath\n },\n arrow: {\n main: arrow,\n path: arrowPath\n }\n }\n }\n\n public mainFocus(eventType: string | null): void {\n // Trigger focus but dont scroll to it\n // Need for prevent refocus the element if event is not keyboard event.\n // For example if event is mouse click or tachpad click this condition prevent refocus on element\n // because click by mouse change focus position and not need return focus to element.\n if (eventType !== 'click') {\n this.main.main.focus({ preventScroll: true })\n }\n }\n\n public placeholder(): HTMLDivElement {\n // Figure out if there is a placeholder option\n const placeholderOption = this.store.filter(\n (o) => o.placeholder,\n false,\n false\n ) as Option[]\n\n // If there is a placeholder option use that\n // If placeholder has an html value, use that\n // If placeholder has a text, use that\n // If nothing is set, use the placeholder text\n let placeholderText = this.settings.placeholderText\n if (placeholderOption.length) {\n if (placeholderOption[0].html !== '') {\n placeholderText = placeholderOption[0].html\n } else if (placeholderOption[0].text !== '') {\n placeholderText = placeholderOption[0].text\n }\n }\n\n // Create placeholder div\n const placeholder = document.createElement('div')\n this.addClasses(placeholder, this.classes.placeholder)\n placeholder.innerHTML = placeholderText\n return placeholder\n }\n\n // Get selected values and append to multiSelected values container\n // and remove those who shouldnt exist\n public renderValues(): void {\n // If single select set placeholder or selected value\n if (!this.settings.isMultiple) {\n this.renderSingleValue()\n return\n }\n\n this.renderMultipleValues()\n\n this.updateDeselectAll()\n }\n\n private renderSingleValue(): void {\n const selected = this.store.filter((o: Option): boolean => {\n return o.selected && !o.placeholder\n }, false, false) as Option[]\n const selectedSingle = selected.length > 0 ? selected[0] : null\n\n // If nothing is seleected use settings placeholder text\n if (!selectedSingle) {\n this.main.values.innerHTML = this.placeholder().outerHTML\n } else {\n // Create single value container\n const singleValue = document.createElement('div')\n this.addClasses(singleValue, this.classes.single)\n if (selectedSingle.html) {\n singleValue.innerHTML = selectedSingle.html\n } else {\n singleValue.innerText = selectedSingle.text\n }\n\n // If there is a selected value, set a single div\n this.main.values.innerHTML = singleValue.outerHTML\n }\n\n // If allowDeselect is false or selected value is empty just hide deselect\n if (!this.settings.allowDeselect || !selected.length) {\n this.addClasses(this.main.deselect.main, this.classes.hide)\n } else {\n this.removeClasses(this.main.deselect.main, this.classes.hide)\n }\n }\n\n private renderMultipleValues(): void {\n // Get various pieces of data\n let currentNodes = this.main.values.childNodes as NodeListOf<HTMLDivElement>\n let selectedOptions = this.store.filter((opt: Option) => {\n // Only grab options that are selected and display is true\n return opt.selected && opt.display\n }, false, false) as Option[]\n\n // If selectedOptions is empty set placeholder\n if (selectedOptions.length === 0) {\n this.main.values.innerHTML = this.placeholder().outerHTML\n return\n } else {\n // If there is a placeholder, remove it\n const placeholder = this.main.values.querySelector(\n '.' + this.classes.getFirst('placeholder')\n )\n if (placeholder) {\n placeholder.remove()\n }\n }\n\n // If multiString is enabled, render a single text element containing the\n // selected values joined by commas instead of individual value pills.\n // CSS truncates the text with an ellipsis when it exceeds the container width.\n if (this.settings.multiString) {\n let commaOptions = selectedOptions\n if (this.settings.keepOrder) {\n commaOptions = this.store.selectedOrderOptions(commaOptions)\n }\n\n const commaValue = document.createElement('div')\n this.addClasses(commaValue, this.classes.multiString)\n commaValue.textContent = commaOptions\n .map((o: Option) => o.text)\n .join(', ')\n\n if (this.settings.showOptionTooltips) {\n commaValue.setAttribute('title', commaValue.textContent)\n }\n\n this.main.values.innerHTML = commaValue.outerHTML\n return\n }\n\n // If selectedOptions is greater than maxItems, set maxValuesMessage\n if (selectedOptions.length > this.settings.maxValuesShown) {\n // Creating the element that shows the number of selected items\n const singleValue = document.createElement('div')\n this.addClasses(singleValue, this.classes.max)\n singleValue.textContent = this.settings.maxValuesMessage.replace(\n '{number}',\n selectedOptions.length.toString()\n )\n\n // If there is a selected value, set a single div\n this.main.values.innerHTML = singleValue.outerHTML\n return\n } else {\n // If there is a message, remove it\n const maxValuesMessage = this.main.values.querySelector(\n '.' + this.classes.getFirst('max')\n )\n if (maxValuesMessage) {\n maxValuesMessage.remove()\n }\n }\n\n // Lets check for data selected order\n if (this.settings.keepOrder) {\n selectedOptions = this.store.selectedOrderOptions(selectedOptions)\n }\n\n // Loop through currentNodes and only include ones that are not in selectedIDs\n let removeNodes: HTMLDivElement[] = []\n for (let i = 0; i < currentNodes.length; i++) {\n const node = currentNodes[i]\n const id = node.getAttribute('data-id')\n if (id) {\n // Check if id is in selectedOptions\n const found = selectedOptions.filter((opt: Option) => {\n return opt.id === id\n }, false)\n\n // If not found, add to removeNodes\n if (!found.length) {\n removeNodes.push(node)\n }\n }\n }\n\n const animationDuration = getAnimationTimeout(\n this.content.main,\n this.settings.timeoutDelay\n )\n\n // Loop through and remove\n for (const n of removeNodes) {\n this.addClasses(n, this.classes.valueOut)\n void waitForAnimationEnd(n, 'ss-valueOut', animationDuration).then(() => {\n if (this.main.values.hasChildNodes() && this.main.values.contains(n)) {\n this.main.values.removeChild(n)\n }\n })\n }\n\n // Add values that dont currently exist\n currentNodes = this.main.values.childNodes as NodeListOf<HTMLDivElement>\n for (let d = 0; d < selectedOptions.length; d++) {\n let shouldAdd = true\n for (let i = 0; i < currentNodes.length; i++) {\n if (selectedOptions[d].id === String(currentNodes[i].dataset.id)) {\n shouldAdd = false\n }\n }\n\n // If shouldAdd, insertAdjacentElement it to the values container in the order of the selectedOptions\n if (shouldAdd) {\n // If keepOrder is true, we will just append it to the end\n if (this.settings.keepOrder) {\n this.main.values.appendChild(this.multipleValue(selectedOptions[d]))\n } else {\n // else we will insert it in the order of the selectedOptions\n if (currentNodes.length === 0) {\n this.main.values.appendChild(this.multipleValue(selectedOptions[d]))\n } else if (d === 0) {\n this.main.values.insertBefore(\n this.multipleValue(selectedOptions[d]),\n currentNodes[d]\n )\n } else {\n currentNodes[d - 1].insertAdjacentElement(\n 'afterend',\n this.multipleValue(selectedOptions[d])\n )\n }\n }\n }\n }\n\n this.updateMultipleValueDeleteVisibility()\n }\n\n private isAtMinSelected(): boolean {\n return (\n this.settings.isMultiple &&\n this.settings.minSelected > 0 &&\n this.store.getSelectedOptions().length <= this.settings.minSelected\n )\n }\n\n private getMinimumSelectionIds(): string[] {\n let selected = this.store.getSelectedOptions()\n if (this.settings.keepOrder) {\n selected = this.store.selectedOrderOptions(selected)\n }\n\n return selected\n .slice(0, this.settings.minSelected)\n .map((option) => option.id)\n }\n\n private updateMultipleValueDeleteVisibility(): void {\n if (!this.settings.isMultiple || this.settings.multiString) {\n return\n }\n\n const canRemove = !this.isAtMinSelected()\n const deleteButtons = this.main.values.querySelectorAll(\n '.' + this.classes.getFirst('valueDelete')\n )\n\n for (const deleteButton of deleteButtons) {\n if (canRemove) {\n this.removeClasses(deleteButton as HTMLElement, this.classes.hide)\n } else {\n this.addClasses(deleteButton as HTMLElement, this.classes.hide)\n }\n }\n }\n\n public multipleValue(option: Option): HTMLDivElement {\n const value = document.createElement('div')\n this.addClasses(value, this.classes.value)\n value.dataset.id = option.id\n\n const text = document.createElement('div')\n this.addClasses(text, this.classes.valueText)\n text.textContent = option.text // For multiple values always use text\n value.appendChild(text)\n\n // Only add deletion if the option is not mandatory\n if (!option.mandatory) {\n // Create delete div element\n const deleteDiv = document.createElement('div')\n this.addClasses(deleteDiv, this.classes.valueDelete)\n deleteDiv.setAttribute('tabindex', '0') // Make the div focusable for tab navigation\n deleteDiv.setAttribute('role', 'button')\n deleteDiv.setAttribute(\n 'aria-label',\n `${this.settings.removeText} ${option.text}`\n )\n\n if (this.isAtMinSelected()) {\n this.addClasses(deleteDiv, this.classes.hide)\n }\n\n // Add delete onclick event\n deleteDiv.onclick = (e: Event) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Dont do anything if disabled\n if (this.settings.disabled) {\n return\n }\n\n // By Default we will delete\n let shouldDelete = true\n const before = this.store.getSelectedOptions()\n const after = before.filter((o) => {\n return o.selected && o.id !== option.id\n }, true)\n\n // Check if minSelected is set and if after length so, return\n if (\n this.settings.minSelected &&\n after.length < this.settings.minSelected\n ) {\n return\n }\n\n // If there is a beforeDeselect function run it\n if (this.callbacks.beforeChange) {\n shouldDelete = this.callbacks.beforeChange(after, before) === true\n }\n\n if (shouldDelete) {\n // Loop through after and append ids to a variable called selected\n let selectedIds: string[] = []\n for (const o of after) {\n if (o instanceof Optgroup) {\n for (const c of o.options) {\n if (c.id) {\n selectedIds.push(c.id)\n }\n }\n }\n\n if (o instanceof Option) {\n selectedIds.push(o.id)\n }\n }\n this.callbacks.setSelected(selectedIds, false)\n\n // Check if we need to close the dropdown\n if (this.settings.closeOnSelect) {\n this.requestClose('deselect', { selectionChanged: true })\n }\n\n // Run afterChange callback\n if (this.callbacks.afterChange) {\n this.callbacks.afterChange(after)\n }\n\n this.updateDeselectAll()\n this.updateMultipleValueDeleteVisibility()\n }\n }\n\n // Add delete svg\n const deleteSvg = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'svg'\n )\n deleteSvg.setAttribute('viewBox', '0 0 100 100')\n const deletePath = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n deletePath.setAttribute('d', this.classes.optionDelete)\n deleteSvg.appendChild(deletePath)\n deleteDiv.appendChild(deleteSvg)\n\n value.appendChild(deleteDiv)\n\n // Add keydown event listener for keyboard navigation (Enter key)\n deleteDiv.onkeydown = (e) => {\n if (e.key === 'Enter') {\n deleteDiv.click() // Trigger the click event when Enter is pressed\n }\n }\n }\n\n return value\n }\n\n public contentDiv(): Content {\n const main = document.createElement('div')\n\n // Add id to data-id\n main.dataset.id = this.settings.id\n // main.id = this.settings.id + '-content' // Remove for now as it is not needed and add duplicate id errors\n\n // Add search\n const search = this.searchDiv()\n main.appendChild(search.main)\n\n // Screen reader announcements for search result updates\n const status = document.createElement('div')\n this.addClasses(status, this.classes.status)\n status.setAttribute('aria-live', 'polite')\n status.setAttribute('aria-atomic', 'true')\n status.setAttribute('role', 'status')\n main.appendChild(status)\n\n // Add list\n const list = this.listDiv()\n main.appendChild(list)\n\n return {\n main: main,\n search: search,\n status: status,\n list: list\n }\n }\n\n private announce(message: string): void {\n if (!this.settings.showSearch) {\n return\n }\n\n this.content.status.textContent = message\n }\n\n public moveContent(): void {\n if (this.isModalViewActive()) {\n return\n }\n\n if (this.settings.contentPosition === 'relative') {\n this.moveContentBelow()\n return\n }\n\n if (this.settings.openPosition === 'down') {\n this.moveContentBelow()\n return\n } else if (this.settings.openPosition === 'up') {\n this.moveContentAbove()\n return\n }\n\n if (this.putContent() === 'up') {\n this.moveContentAbove()\n } else {\n this.moveContentBelow()\n }\n }\n\n /** Track trigger/content layout changes and reposition the dropdown panel. */\n public startPositionTracking(): void {\n if (this.settings.contentPosition !== 'absolute' || this.isModalViewActive()) {\n return\n }\n\n this.stopPositionTracking()\n\n if (typeof ResizeObserver === 'undefined') {\n return\n }\n\n this.positionObserver = new ResizeObserver(() => {\n if (!this.settings.isOpen) {\n return\n }\n\n cancelAnimationFrame(this.positionObserverRaf)\n this.positionObserverRaf = requestAnimationFrame(() => {\n this.moveContent()\n })\n })\n\n this.observePositionTargets()\n }\n\n public stopPositionTracking(): void {\n cancelAnimationFrame(this.positionObserverRaf)\n this.positionObserver?.disconnect()\n this.positionObserver = null\n this.cancelOverflowShift()\n }\n\n private observePositionTargets(): void {\n if (!this.positionObserver) {\n return\n }\n\n const observed = new Set<Element>()\n const observe = (el: Element | null): void => {\n if (!el || observed.has(el)) {\n return\n }\n\n observed.add(el)\n this.positionObserver!.observe(el)\n }\n\n observe(this.main.main)\n // Do not observe content — our own overflow/position updates resize the panel\n // and would re-enter moveContent() causing horizontal jitter at the viewport edge.\n\n let parent: HTMLElement | null = this.main.main.parentElement\n const stopAt = this.settings.contentLocation\n\n for (let depth = 0; parent && depth < 8; depth++) {\n observe(parent)\n if (parent === stopAt) {\n break\n }\n parent = parent.parentElement\n }\n }\n\n public searchDiv(): Search {\n const main = document.createElement('div')\n const input = document.createElement('input')\n const addable = document.createElement('div')\n this.addClasses(main, this.classes.search)\n\n // Setup search return object\n const searchReturn: Search = {\n main,\n input\n }\n\n // We still want the search to be tabable but not shown\n if (!this.settings.showSearch) {\n this.addClasses(main, this.classes.hide)\n input.readOnly = true\n }\n\n input.type = 'search'\n input.placeholder = this.settings.searchPlaceholder\n input.tabIndex = -1\n input.setAttribute('aria-label', this.settings.searchPlaceholder)\n input.setAttribute('aria-autocomplete', 'list')\n input.setAttribute('autocapitalize', 'off')\n input.setAttribute('autocomplete', 'off')\n input.setAttribute('autocorrect', 'off')\n // Hide from screen readers by default (shown when opened)\n input.setAttribute('aria-hidden', 'true')\n\n input.oninput = debounce((e: Event) => {\n this.callbacks.search((e.target as HTMLInputElement).value)\n }, 100)\n\n // Deal with keyboard events on search input field\n input.onkeydown = (e: KeyboardEvent): boolean => {\n // Convert above if else statemets to switch\n switch (e.key) {\n case 'ArrowUp':\n case 'ArrowDown':\n e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up')\n return false\n case 'Tab':\n // When tabbing close the dropdown\n // which will also focus on main div\n // and then continuing normal tabbing\n this.requestClose('tab')\n return true // Continue doing normal tabbing\n case 'Escape':\n this.requestClose('escape')\n return false\n case 'Enter':\n // Check if there's a highlighted option first\n const highlightedEnter = this.content.list.querySelector(\n '.' + this.classes.getFirst('highlighted')\n ) as HTMLDivElement\n if (highlightedEnter) {\n // If an option is highlighted, select it (even if addable is enabled)\n highlightedEnter.click()\n return false\n } else if (this.callbacks.addable) {\n // If no option is highlighted and addable is enabled, add new item\n addable.click()\n return false\n }\n return true\n }\n\n return true // Allow normal typing\n }\n\n main.appendChild(input)\n\n // If addable is enabled, add the addable div\n if (this.callbacks.addable) {\n // Add main class\n this.addClasses(addable, this.classes.addable)\n\n // Add svg icon\n const plus = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n plus.setAttribute('viewBox', '0 0 100 100')\n const plusPath = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n plusPath.setAttribute('d', this.classes.addablePath)\n plus.appendChild(plusPath)\n addable.appendChild(plus)\n\n // Add click event to addable div\n addable.onclick = (e: Event) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Do nothing if addable is not set\n if (!this.callbacks.addable) {\n return\n }\n\n // Grab input value\n const inputValue = this.content.search.input.value.trim()\n if (inputValue === '') {\n this.content.search.input.focus()\n return\n }\n\n // Run finish will be ran at the end of the addable function.\n // Reason its in a function is so we can run it after the\n // addable function is done for promise based addables\n const runFinish = (oo: Partial<Option>) => {\n let newOption = new Option(oo)\n\n // Call addOption to add the new option\n this.callbacks.addOption(newOption)\n\n // set selected value for single and multiple\n if (this.settings.isMultiple) {\n let ids = this.store.getSelected()\n ids.push(newOption.id)\n this.callbacks.setSelected(ids, true)\n } else {\n this.callbacks.setSelected([newOption.id], true)\n }\n\n // Clear search\n this.callbacks.search('')\n\n // Close it only if closeOnSelect = true\n if (this.settings.closeOnSelect) {\n const animationDuration = getAnimationDuration(this.content.main)\n setTimeout(() => {\n this.requestClose('select', { selectionChanged: true })\n }, animationDuration)\n }\n }\n\n // Call addable callback\n const addableValue = this.callbacks.addable(inputValue)\n\n // If addableValue is false, undefined or null, do nothing\n if (\n addableValue === false ||\n addableValue === undefined ||\n addableValue === null\n ) {\n return\n }\n\n // If addableValue is a promise, wait for it to resolve\n if (addableValue instanceof Promise) {\n addableValue.then((value) => {\n if (typeof value === 'string') {\n runFinish({\n text: value,\n value: value\n })\n } else if (addableValue instanceof Error) {\n this.renderError(addableValue.message)\n } else {\n runFinish(value)\n }\n })\n } else if (typeof addableValue === 'string') {\n runFinish({\n text: addableValue,\n value: addableValue\n })\n } else if (addableValue instanceof Error) {\n this.renderError(addableValue.message)\n } else {\n runFinish(addableValue)\n }\n\n return\n }\n main.appendChild(addable)\n\n // Add the addable to the search return\n searchReturn.addable = {\n main: addable,\n svg: plus,\n path: plusPath\n }\n }\n\n return searchReturn\n }\n\n public searchFocus(): void {\n this.content.search.input.focus({ preventScroll: true })\n }\n\n public getOptions(\n notPlaceholder = false,\n notDisabled = false,\n notHidden = false\n ): HTMLDivElement[] {\n // Put together query string\n let query = '.' + this.classes.getFirst('option')\n if (notPlaceholder) {\n query += ':not(.' + this.classes.getFirst('placeholder') + ')'\n }\n if (notDisabled) {\n query += ':not(.' + this.classes.getFirst('disabled') + ')'\n }\n if (notHidden) {\n query += ':not(.' + this.classes.getFirst('hide') + ')'\n }\n\n return Array.from(this.content.list.querySelectorAll(query))\n }\n\n // highlightUp is used to highlight the previous option in the list\n public highlight(dir: 'up' | 'down'): void {\n // Get full list of options in list\n const options = this.getOptions(true, true, true)\n\n // If there are no options, do nothing\n if (options.length === 0) {\n return\n }\n\n // If length is 1, highlight it\n if (options.length === 1) {\n // Check if option doesnt already have highlighted class\n if (\n !options[0].classList.contains(this.classes.getFirst('highlighted'))\n ) {\n this.addClasses(options[0], this.classes.highlighted)\n return\n }\n }\n\n // Loop through options and see if there are no highlighted ones\n let highlighted = false\n for (const o of options) {\n if (o.classList.contains(this.classes.getFirst('highlighted'))) {\n highlighted = true\n }\n }\n\n // If no highlighted, see if any are selected and if so highlight selected first one\n if (!highlighted) {\n for (const o of options) {\n if (o.classList.contains(this.classes.getFirst('selected'))) {\n this.addClasses(o, this.classes.highlighted)\n break\n }\n }\n }\n\n // Loop through options and find the highlighted one\n for (let i = 0; i < options.length; i++) {\n // Found highlighted option\n if (options[i].classList.contains(this.classes.getFirst('highlighted'))) {\n const prevOption = options[i]\n // Remove highlighted class from current one\n this.removeClasses(prevOption, this.classes.highlighted)\n\n // If previous option has parent classes ss-optgroup with ss-open then click it\n const prevParent = prevOption.parentElement\n if (\n prevParent &&\n prevParent.classList.contains(this.classes.getFirst('mainOpen'))\n ) {\n const optgroupLabel = prevParent.querySelector(\n '.' + this.classes.getFirst('optgroupLabel')\n ) as HTMLDivElement\n if (optgroupLabel) {\n optgroupLabel.click()\n }\n }\n\n // Highlight the next one\n let selectOption =\n options[\n dir === 'down'\n ? i + 1 < options.length\n ? i + 1\n : 0\n : i - 1 >= 0\n ? i - 1\n : options.length - 1\n ]\n this.addClasses(selectOption, this.classes.highlighted)\n this.ensureElementInView(this.content.list, selectOption)\n\n // Update aria-activedescendant for screen readers\n if (selectOption.id) {\n this.main.main.setAttribute('aria-activedescendant', selectOption.id)\n }\n\n // If selected option has parent classes ss-optgroup with ss-close then click it\n const selectParent = selectOption.parentElement\n if (\n selectParent &&\n selectParent.classList.contains(this.classes.getFirst('close'))\n ) {\n const optgroupLabel = selectParent.querySelector(\n '.' + this.classes.getFirst('optgroupLabel')\n ) as HTMLDivElement\n if (optgroupLabel) {\n optgroupLabel.click()\n }\n }\n\n return\n }\n }\n\n // If we get here, there is no highlighted option\n // So we will highlight the first or last based upon direction\n const firstHighlight = options[dir === 'down' ? 0 : options.length - 1]\n this.addClasses(firstHighlight, this.classes.highlighted)\n\n // Update aria-activedescendant for screen readers\n if (firstHighlight.id) {\n this.main.main.setAttribute('aria-activedescendant', firstHighlight.id)\n }\n\n // Scroll to highlighted one\n this.ensureElementInView(this.content.list, firstHighlight)\n }\n\n // Create main container that options will reside\n public listDiv(): HTMLDivElement {\n const options = document.createElement('div')\n this.addClasses(options, this.classes.list)\n\n // Add id for ARIA controls reference\n const listId = this.settings.id + '-list'\n options.id = listId\n options.dataset.id = listId\n\n return options\n }\n\n public renderError(error: string) {\n this.optionsListIsFullData = false\n // Clear out innerHtml\n this.content.list.innerHTML = ''\n\n const errorDiv = document.createElement('div')\n this.addClasses(errorDiv, this.classes.error)\n errorDiv.textContent = error\n this.content.list.appendChild(errorDiv)\n }\n\n public renderSearching() {\n this.optionsListIsFullData = false\n // Clear out innerHtml\n this.content.list.innerHTML = ''\n\n const searchingDiv = document.createElement('div')\n this.addClasses(searchingDiv, this.classes.searching)\n searchingDiv.textContent = this.settings.searchingText\n this.content.list.appendChild(searchingDiv)\n this.announce(this.settings.searchingText)\n }\n\n // Take in data and add options to\n public renderOptions(data: (Option | Optgroup)[]): void {\n this.lastSearchFilterTerm = ''\n this.lastRenderedOptions = data\n .map((o) =>\n o instanceof Option ? [o] : o.options.map((po) => new Option(po))\n )\n .flat()\n\n // Clear out innerHtml\n this.content.list.innerHTML = ''\n\n // If no results show no results text\n if (data.length === 0) {\n this.optionsListIsFullData = false\n const noResults = document.createElement('div')\n this.addClasses(noResults, this.classes.search)\n\n //\n if (this.callbacks.addable) {\n const addableMessage = this.settings.addableText.replace(\n '{value}',\n this.content.search.input.value\n )\n noResults.innerHTML = addableMessage\n this.announce(addableMessage)\n } else {\n noResults.innerHTML = this.settings.searchText\n this.announce(this.settings.searchText)\n }\n this.content.list.appendChild(noResults)\n return\n }\n\n // If settings has allowDeselect and isSingle, add empty placeholder in the event they want to deselect\n if (this.settings.allowDeselect && !this.settings.isMultiple) {\n // Check if store options have a placeholder\n const placeholderOption = this.store.filter(\n (o) => o.placeholder,\n false,\n false\n ) as Option[]\n if (!placeholderOption.length) {\n this.store.addOption(\n new Option({\n text: '',\n value: '',\n selected: false,\n placeholder: true\n }),\n true\n )\n }\n }\n\n // Append individual options to div container\n const fragment = document.createDocumentFragment()\n for (const d of data) {\n // Create optgroup\n if (d instanceof Optgroup) {\n // Create optgroup\n const optgroupEl = document.createElement('div')\n this.addClasses(optgroupEl, this.classes.optgroup)\n\n // Create label\n const optgroupLabel = document.createElement('div')\n this.addClasses(optgroupLabel, this.classes.optgroupLabel)\n optgroupEl.appendChild(optgroupLabel)\n\n // Create label text div element\n const optgroupLabelText = document.createElement('div')\n this.addClasses(optgroupLabelText, this.classes.optgroupLabelText)\n optgroupLabelText.textContent = d.label\n optgroupLabel.appendChild(optgroupLabelText)\n\n // Create options container\n const optgroupActions = document.createElement('div')\n this.addClasses(optgroupActions, this.classes.optgroupActions)\n optgroupLabel.appendChild(optgroupActions)\n\n // If selectByGroup is true and isMultiple then add click event to label\n if (this.settings.isMultiple && d.selectAll) {\n // Create new div to hold a checkbox svg\n const selectAll = document.createElement('div')\n this.addClasses(selectAll, this.classes.optgroupSelectAll)\n\n // Check options and if all are selected, if so add class selected\n const allSelected = this.isOptgroupAllSelected(d.options as Option[])\n\n // Add class if all selected\n if (allSelected) {\n this.addClasses(selectAll, this.classes.selected)\n }\n\n // Add select all text span\n const selectAllLabel = document.createElement('span')\n selectAllLabel.textContent = this.optgroupSelectAllLabel(allSelected)\n selectAll.appendChild(selectAllLabel)\n\n // Create new svg for checkbox\n const selectAllSvg = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'svg'\n )\n selectAllSvg.setAttribute('viewBox', '0 0 100 100')\n selectAll.appendChild(selectAllSvg)\n\n // Create new path for box\n const selectAllBox = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n selectAllBox.setAttribute('d', this.classes.optgroupSelectAllBox)\n selectAllSvg.appendChild(selectAllBox)\n\n // Create new path for check\n const selectAllCheck = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n selectAllCheck.setAttribute('d', this.classes.optgroupSelectAllCheck)\n selectAllSvg.appendChild(selectAllCheck)\n\n // Add click event listener to select all\n selectAll.addEventListener('click', (e: MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Get the store current selected values\n const currentSelected = this.store.getSelected()\n const allSelectedNow = this.isOptgroupAllSelected(\n d.options as Option[],\n new Set(currentSelected)\n )\n\n // If all selected, remove all options from selected\n if (allSelectedNow) {\n // Put together new list minus all options in this optgroup\n const newSelected = currentSelected.filter((s) => {\n for (const o of d.options) {\n if (s === o.id) {\n return false\n }\n }\n\n return true\n })\n\n this.callbacks.setSelected(newSelected, true)\n return\n } else {\n // Put together new list with all options in this optgroup\n let optionIds = d.options\n .map((o) => o.id)\n .filter((id) => id !== undefined)\n const newSelected = currentSelected.concat(optionIds)\n\n // Loop through options and if they don't exist in the store\n // run addOption callback\n for (const o of d.options) {\n if (o.id && !this.store.getOptionByID(o.id)) {\n this.callbacks.addOption(new Option(o))\n }\n }\n\n this.callbacks.setSelected(newSelected, true)\n return\n }\n })\n\n // Append select all to label\n optgroupActions.appendChild(selectAll)\n }\n\n // If optgroup has collapsable\n if (d.closable !== 'off') {\n // Create new div to hold a checkbox svg\n const optgroupClosable = document.createElement('div')\n this.addClasses(optgroupClosable, this.classes.optgroupClosable)\n\n // Create svg arrow\n const optgroupClosableSvg = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'svg'\n )\n optgroupClosableSvg.setAttribute('viewBox', '0 0 100 100')\n this.addClasses(optgroupClosableSvg, this.classes.arrow)\n optgroupClosable.appendChild(optgroupClosableSvg)\n\n // Create new path for arrow\n const optgroupClosableArrow = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n optgroupClosableSvg.appendChild(optgroupClosableArrow)\n\n // If any options are selected or someone is searching, set optgroup to open\n if (\n d.options.some((o) => o.selected) ||\n this.content.search.input.value.trim() !== ''\n ) {\n this.addClasses(optgroupClosable, this.classes.mainOpen)\n optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen)\n } else if (d.closable === 'open') {\n this.addClasses(optgroupEl, this.classes.mainOpen)\n optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen)\n } else if (d.closable === 'close') {\n this.addClasses(optgroupEl, this.classes.close)\n optgroupClosableArrow.setAttribute('d', this.classes.arrowClose)\n }\n\n // Add click event listener to close\n optgroupLabel.addEventListener('click', (e: MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n\n const isOpen = this.isClosableOptgroupOpen(\n optgroupEl,\n optgroupClosable\n )\n\n if (!isOpen) {\n this.closeOtherClosableOptgroups(optgroupEl)\n this.removeClasses(optgroupEl, this.classes.close)\n this.removeClasses(optgroupClosable, this.classes.mainOpen)\n this.addClasses(optgroupEl, this.classes.mainOpen)\n optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen)\n } else {\n this.removeClasses(optgroupEl, this.classes.mainOpen)\n this.removeClasses(optgroupClosable, this.classes.mainOpen)\n this.addClasses(optgroupEl, this.classes.close)\n optgroupClosableArrow.setAttribute('d', this.classes.arrowClose)\n }\n })\n\n // Append close to label\n optgroupActions.appendChild(optgroupClosable)\n }\n\n // Add optgroup label\n optgroupEl.appendChild(optgroupLabel)\n\n // Loop through options\n for (const option of d.options) {\n optgroupEl.appendChild(this.option(new Option(option)))\n fragment.appendChild(optgroupEl)\n }\n }\n\n // Create option\n if (d instanceof Option) {\n fragment.appendChild(this.option(d as Option))\n }\n }\n\n // Append fragment to list\n this.content.list.appendChild(fragment)\n this.setOptionsListFullData(data)\n this.announce(\n this.settings.resultsText.replace(\n '{count}',\n String(this.lastRenderedOptions.length)\n )\n )\n }\n\n /** True when the list DOM contains every store option (local search can show/hide in place). */\n public canFilterOptionsInPlace(): boolean {\n if (!this.optionsListIsFullData) {\n return false\n }\n\n return (\n this.content.list.querySelector(\n '.' + this.classes.getFirst('option')\n ) !== null\n )\n }\n\n public resetSearchFilterState(): void {\n this.lastSearchFilterTerm = ''\n }\n\n /** Filter visible options by search without rebuilding the list. */\n public filterOptionsInPlace(\n search: string,\n searchFilter: (opt: Option, search: string) => boolean\n ): void {\n const searchTrim = search.trim()\n if (searchTrim === this.lastSearchFilterTerm) {\n return\n }\n this.lastSearchFilterTerm = searchTrim\n\n const visibleOptions: Option[] = []\n const optionEls = this.content.list.querySelectorAll(\n '.' + this.classes.getFirst('option')\n ) as NodeListOf<HTMLDivElement>\n\n for (const optionEl of optionEls) {\n const id = optionEl.dataset.id\n if (!id) {\n continue\n }\n\n const storeOption = this.store.getOptionByID(id)\n if (!storeOption) {\n continue\n }\n\n const isPermanentlyHidden =\n storeOption.placeholder ||\n !storeOption.display ||\n (storeOption.selected && this.settings.hideSelected)\n\n const matchesSearch = searchFilter(storeOption, searchTrim)\n\n if (isPermanentlyHidden || !matchesSearch) {\n this.addClasses(optionEl, this.classes.hide)\n this.removeClasses(optionEl, this.classes.highlighted)\n } else {\n this.removeClasses(optionEl, this.classes.hide)\n this.setOptionElementContent(optionEl, storeOption, searchTrim)\n visibleOptions.push(storeOption)\n }\n\n if (storeOption.selected) {\n this.addClasses(optionEl, this.classes.selected)\n optionEl.setAttribute('aria-selected', 'true')\n } else {\n this.removeClasses(optionEl, this.classes.selected)\n optionEl.setAttribute('aria-selected', 'false')\n }\n }\n\n this.lastRenderedOptions = visibleOptions\n this.updateOptgroupVisibilityAfterSearch(searchTrim)\n\n if (visibleOptions.length === 0) {\n this.updateSearchResultsMessage(0, searchTrim)\n } else {\n this.removeListSearchMessage()\n this.announce(\n this.settings.resultsText.replace(\n '{count}',\n String(visibleOptions.length)\n )\n )\n }\n\n this.updateOptgroupSelectAllStates()\n }\n\n private setOptionsListFullData(data: (Option | Optgroup)[]): void {\n const storeOptions = this.store.getDataOptions(false)\n const renderedOptions = data\n .map((o) =>\n o instanceof Option ? [o] : o.options.map((po) => new Option(po))\n )\n .flat()\n\n if (renderedOptions.length !== storeOptions.length) {\n this.optionsListIsFullData = false\n return\n }\n\n const storeIds = new Set(storeOptions.map((o) => o.id))\n this.optionsListIsFullData = renderedOptions.every((o) =>\n storeIds.has(o.id)\n )\n }\n\n private isClosableOptgroupOpen(\n optgroupEl: HTMLElement,\n optgroupClosable: HTMLElement\n ): boolean {\n if (optgroupEl.classList.contains(this.classes.getFirst('close'))) {\n return false\n }\n\n return (\n optgroupEl.classList.contains(this.classes.getFirst('mainOpen')) ||\n optgroupClosable.classList.contains(this.classes.getFirst('mainOpen'))\n )\n }\n\n private closeClosableOptgroup(optgroupEl: HTMLElement): void {\n const closable = optgroupEl.querySelector(\n '.' + this.classes.getFirst('optgroupClosable')\n ) as HTMLElement | null\n if (!closable) {\n return\n }\n\n if (optgroupEl.classList.contains(this.classes.getFirst('close'))) {\n return\n }\n\n this.removeClasses(optgroupEl, this.classes.mainOpen)\n this.removeClasses(closable, this.classes.mainOpen)\n this.addClasses(optgroupEl, this.classes.close)\n\n const arrow = closable.querySelector('path')\n if (arrow) {\n arrow.setAttribute('d', this.classes.arrowClose)\n }\n }\n\n private closeOtherClosableOptgroups(exceptOptgroupEl: HTMLElement): void {\n const optgroups = this.content.list.querySelectorAll(\n '.' + this.classes.getFirst('optgroup')\n )\n\n for (const optgroupEl of optgroups) {\n if (optgroupEl === exceptOptgroupEl) {\n continue\n }\n\n this.closeClosableOptgroup(optgroupEl as HTMLElement)\n }\n }\n\n private updateOptgroupVisibilityAfterSearch(searchTrim: string): void {\n const optgroups = this.content.list.querySelectorAll(\n '.' + this.classes.getFirst('optgroup')\n )\n\n for (const optgroupEl of optgroups) {\n const optionEls = optgroupEl.querySelectorAll(\n '.' + this.classes.getFirst('option')\n ) as NodeListOf<HTMLDivElement>\n\n let hasVisibleOption = false\n for (const optionEl of optionEls) {\n if (!optionEl.classList.contains(this.classes.getFirst('hide'))) {\n hasVisibleOption = true\n break\n }\n }\n\n if (!hasVisibleOption) {\n this.addClasses(optgroupEl as HTMLDivElement, this.classes.hide)\n continue\n }\n\n this.removeClasses(optgroupEl as HTMLDivElement, this.classes.hide)\n\n if (searchTrim !== '') {\n this.removeClasses(optgroupEl as HTMLDivElement, this.classes.close)\n this.addClasses(optgroupEl as HTMLDivElement, this.classes.mainOpen)\n }\n }\n }\n\n private updateSearchResultsMessage(\n visibleCount: number,\n searchTrim: string\n ): void {\n this.removeListSearchMessage()\n\n if (visibleCount > 0) {\n return\n }\n\n const noResults = document.createElement('div')\n this.addClasses(noResults, this.classes.search)\n\n if (this.callbacks.addable) {\n const addableMessage = this.settings.addableText.replace(\n '{value}',\n searchTrim\n )\n noResults.innerHTML = addableMessage\n this.announce(addableMessage)\n } else {\n noResults.innerHTML = this.settings.searchText\n this.announce(this.settings.searchText)\n }\n\n this.content.list.appendChild(noResults)\n }\n\n private removeListSearchMessage(): void {\n const messages = this.content.list.querySelectorAll(\n '.' + this.classes.getFirst('search')\n )\n messages.forEach((message) => message.remove())\n }\n\n private setOptionElementContent(\n optionEl: HTMLDivElement,\n option: Option,\n search: string\n ): void {\n const searchTrim = search.trim()\n if (this.settings.searchHighlight && searchTrim !== '') {\n optionEl.innerHTML = this.highlightText(\n option.html !== '' ? option.html : option.text,\n searchTrim,\n this.classes.searchHighlighter\n )\n } else if (option.html !== '') {\n optionEl.innerHTML = option.html\n } else {\n optionEl.textContent = option.text\n }\n\n if (this.settings.showOptionTooltips && optionEl.textContent) {\n optionEl.setAttribute('title', optionEl.textContent)\n } else {\n optionEl.removeAttribute('title')\n }\n }\n\n /** True when option nodes exist in the list (selection can sync without re-searching). */\n public hasRenderedOptions(): boolean {\n return (\n this.content.list.querySelector(\n '.' + this.classes.getFirst('option')\n ) !== null\n )\n }\n\n /** True when the open list already has options and search is not filtering. */\n public canUpdateOptionSelectionInPlace(): boolean {\n if (this.content.search.input.value.trim() !== '') {\n return false\n }\n\n return this.hasRenderedOptions()\n }\n\n /** Sync selected/hidden state on existing option nodes without rebuilding the list. */\n public updateOptionSelection(): void {\n const selectedIds = new Set(this.store.getSelected())\n const optionEls = this.content.list.querySelectorAll(\n '.' + this.classes.getFirst('option')\n ) as NodeListOf<HTMLDivElement>\n\n let lastSelectedEl: HTMLDivElement | null = null\n\n for (const optionEl of optionEls) {\n const id = optionEl.dataset.id\n if (!id) {\n continue\n }\n\n const storeOption = this.store.getOptionByID(id)\n if (!storeOption) {\n continue\n }\n\n const isSelected = selectedIds.has(id)\n\n if (isSelected) {\n this.addClasses(optionEl, this.classes.selected)\n optionEl.setAttribute('aria-selected', 'true')\n lastSelectedEl = optionEl\n } else {\n this.removeClasses(optionEl, this.classes.selected)\n optionEl.setAttribute('aria-selected', 'false')\n }\n\n if (this.settings.hideSelected) {\n if (isSelected) {\n this.addClasses(optionEl, this.classes.hide)\n } else {\n this.removeClasses(optionEl, this.classes.hide)\n if (!storeOption.display) {\n this.addClasses(optionEl, this.classes.hide)\n }\n }\n }\n }\n\n if (!this.settings.isMultiple && lastSelectedEl) {\n this.main.main.setAttribute('aria-activedescendant', lastSelectedEl.id)\n } else if (!this.settings.isMultiple && selectedIds.size === 0) {\n this.main.main.removeAttribute('aria-activedescendant')\n }\n\n this.updateOptgroupSelectAllStates()\n }\n\n private updateOptgroupSelectAllStates(): void {\n if (!this.settings.isMultiple) {\n return\n }\n\n const selectedIds = new Set(this.store.getSelected())\n const optgroups = this.content.list.querySelectorAll(\n '.' + this.classes.getFirst('optgroup')\n )\n\n for (const optgroupEl of optgroups) {\n const selectAll = optgroupEl.querySelector(\n '.' + this.classes.getFirst('optgroupSelectAll')\n ) as HTMLDivElement | null\n\n if (!selectAll) {\n continue\n }\n\n const optionEls = optgroupEl.querySelectorAll(\n '.' + this.classes.getFirst('option')\n ) as NodeListOf<HTMLDivElement>\n\n let allSelected = optionEls.length > 0\n for (const optionEl of optionEls) {\n const id = optionEl.dataset.id\n if (!id || !selectedIds.has(id)) {\n allSelected = false\n break\n }\n }\n\n if (allSelected) {\n this.addClasses(selectAll, this.classes.selected)\n } else {\n this.removeClasses(selectAll, this.classes.selected)\n }\n\n const selectAllLabel = selectAll.querySelector('span')\n if (selectAllLabel) {\n selectAllLabel.textContent = this.optgroupSelectAllLabel(allSelected)\n }\n }\n }\n\n private optgroupSelectAllLabel(allSelected: boolean): string {\n return allSelected ? 'Unselect All' : 'Select All'\n }\n\n private isOptgroupAllSelected(\n options: Option[],\n selectedIds?: Set<string>\n ): boolean {\n if (options.length === 0) {\n return false\n }\n\n for (const option of options) {\n const isSelected = selectedIds\n ? Boolean(option.id && selectedIds.has(option.id))\n : option.selected\n\n if (!isSelected) {\n return false\n }\n }\n\n return true\n }\n\n // Create option div element\n public option(option: Option): HTMLDivElement {\n // Add hidden placeholder\n if (option.placeholder) {\n const placeholder = document.createElement('div')\n this.addClasses(placeholder, this.classes.option)\n this.addClasses(placeholder, this.classes.hide)\n return placeholder\n }\n\n // Create option\n const optionEl = document.createElement('div')\n optionEl.dataset.id = option.id // Dataset id for identifying an option\n optionEl.id = this.settings.id + '-' + option.id // Unique ID for ARIA references\n this.addClasses(optionEl, this.classes.option)\n optionEl.setAttribute('role', 'option') // WCAG attribute\n if (option.class) {\n option.class.split(' ').forEach((dataClass: string) => {\n optionEl.classList.add(dataClass)\n })\n }\n if (option.style) {\n optionEl.style.cssText = option.style\n }\n\n // Set option content\n this.setOptionElementContent(\n optionEl,\n option,\n this.content.search.input.value\n )\n\n // If option is disabled\n if (!option.display) {\n this.addClasses(optionEl, this.classes.hide)\n }\n\n // If allowed to deselect, null onclick and add disabled\n if (option.disabled) {\n this.addClasses(optionEl, this.classes.disabled)\n }\n\n // If option is selected and hideSelectedOption is true, hide it\n if (option.selected && this.settings.hideSelected) {\n this.addClasses(optionEl, this.classes.hide)\n }\n\n // If option is selected\n if (option.selected) {\n this.addClasses(optionEl, this.classes.selected)\n optionEl.setAttribute('aria-selected', 'true')\n this.main.main.setAttribute('aria-activedescendant', optionEl.id)\n } else {\n this.removeClasses(optionEl, this.classes.selected)\n optionEl.setAttribute('aria-selected', 'false')\n }\n\n // Add click event listener\n optionEl.addEventListener('click', (e: MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Setup variables\n const selectedOptions = this.store.getSelected()\n const element = e.currentTarget as HTMLDivElement\n const elementID = String(element.dataset.id)\n const storeOption = this.store.getOptionByID(elementID) ?? option\n const isCurrentlySelected = selectedOptions.includes(elementID)\n const isCmd = e.ctrlKey || e.metaKey // Cmd (Mac) or Ctrl (Windows/Linux)\n\n // If the option is disabled, do nothing\n if (option.disabled) {\n return\n }\n\n // allowDeselect only applies to single-select mode\n // In multi-select, you can always toggle options on/off\n if (\n !this.settings.isMultiple &&\n isCurrentlySelected &&\n !this.settings.allowDeselect\n ) {\n this.closeOnSingleSelectReclick(storeOption)\n return\n }\n\n // Prevent deselection of mandatory options\n if (isCurrentlySelected && storeOption.mandatory) {\n this.closeOnSingleSelectReclick(storeOption)\n return\n }\n\n // Check limit and do nothing if limit is reached and the option is not selected\n // Also check reverse for min limit and is selected (allow Cmd to bypass minSelected)\n if (\n (this.settings.isMultiple &&\n this.settings.maxSelected <= selectedOptions.length &&\n !isCurrentlySelected) ||\n (this.settings.isMultiple &&\n this.settings.minSelected >= selectedOptions.length &&\n isCurrentlySelected &&\n !isCmd)\n ) {\n return\n }\n\n // Setup variables\n let shouldUpdate = false\n const before = this.store.getSelectedOptions()\n let after = [] as Option[]\n\n // If multiple - mimic native browser multi-select behavior\n if (this.settings.isMultiple) {\n const isCurrentlySelected = before.some(\n (o: Option) => o.id === elementID\n )\n const isShift = e.shiftKey\n\n // Shift+Click: Select range from last clicked to current\n if (isShift && this.lastSelectedOption) {\n const options = this.lastRenderedOptions\n const lastIndex = options.findIndex(\n (o: Option) => o.id === this.lastSelectedOption!.id\n )\n const currentIndex = options.findIndex(\n (o: Option) => o.id === option.id\n )\n\n if (lastIndex >= 0 && currentIndex >= 0) {\n const startIndex = Math.min(lastIndex, currentIndex)\n const endIndex = Math.max(lastIndex, currentIndex)\n const rangeOptions = options.slice(startIndex, endIndex + 1)\n\n // Check if range would exceed maxSelected\n const newSelections = rangeOptions.filter(\n (opt) => !before.find((b) => b.id === opt.id)\n )\n if (\n before.length + newSelections.length <=\n this.settings.maxSelected\n ) {\n // Add range to existing selections\n after = before.concat(newSelections)\n } else {\n // Range too large, keep existing selections\n after = before\n }\n } else {\n after = before\n }\n }\n // Cmd/Ctrl+Click: Toggle selection without affecting others (keeps dropdown open)\n else if (isCmd) {\n if (isCurrentlySelected) {\n // Deselect this option\n after = before.filter((o: Option) => o.id !== elementID)\n } else {\n // Add this option to selection\n after = before.concat(storeOption)\n }\n this.lastSelectedOption = storeOption\n }\n // Regular Click: Toggle this option (add/remove), will close dropdown\n else {\n if (isCurrentlySelected) {\n // Deselect this option\n after = before.filter((o: Option) => o.id !== elementID)\n } else {\n // Add this option to selection\n after = before.concat(storeOption)\n }\n this.lastSelectedOption = storeOption\n }\n }\n\n // If single\n if (!this.settings.isMultiple) {\n if (isCurrentlySelected) {\n // If selected after would remove\n after = []\n } else {\n // If not selected after would add\n after = [storeOption]\n }\n }\n\n // If no beforeOnChange is set automatically update at end\n if (!this.callbacks.beforeChange) {\n shouldUpdate = true\n }\n\n if (this.callbacks.beforeChange) {\n // Check if beforeChange returns false\n if (this.callbacks.beforeChange(after, before) === false) {\n shouldUpdate = false\n } else {\n shouldUpdate = true\n }\n }\n\n if (shouldUpdate) {\n // Check if the option exists in the store\n // if not run addOption callback\n if (!this.store.getOptionByID(elementID)) {\n this.callbacks.addOption(option)\n }\n\n // Get values from after and set as selected\n this.callbacks.setSelected(\n after.map((o: Option) => o.id),\n false\n )\n\n // Close dropdown unless using modifier keys in multi-select\n // (mimics native multi-select behavior where you can keep selecting)\n const isModifierKey = e.ctrlKey || e.metaKey || e.shiftKey // Cmd/Ctrl or Shift\n const shouldClose =\n this.settings.closeOnSelect &&\n !(this.settings.isMultiple && isModifierKey)\n\n if (shouldClose) {\n this.requestClose('select', {\n option: storeOption,\n selectionChanged: this.selectionChanged(before, after)\n })\n }\n\n // callback that the value has changed\n if (this.callbacks.afterChange) {\n this.callbacks.afterChange(after)\n }\n }\n })\n\n return optionEl\n }\n\n public destroy(): void {\n this.stopPositionTracking()\n\n if (this.modalElements) {\n this.unlockBodyScroll()\n if (this.content.main.parentElement === this.modalElements.dialog) {\n this.restoreContentOffscreen()\n }\n this.modalElements.overlay.remove()\n this.modalElements = null\n } else if (this.bodyScrollLocked) {\n this.unlockBodyScroll()\n }\n\n // Remove main\n this.main.main.remove()\n\n // Remove content\n this.content.main.remove()\n\n this.removeDetachedInstanceDom()\n }\n\n /** Remove any leftover main/content/modal nodes for this instance (e.g. on body). */\n private removeDetachedInstanceDom(): void {\n const id = this.settings.id\n const mainClass = this.classes.getFirst('main')\n const contentClass = this.classes.getFirst('content')\n const modalClass = this.classes.getFirst('modalOverlay')\n\n document.querySelectorAll<HTMLElement>(`[data-id=\"${id}\"]`).forEach((el) => {\n if (\n el.classList.contains(mainClass) ||\n el.classList.contains(contentClass) ||\n el.classList.contains(modalClass)\n ) {\n el.remove()\n }\n })\n }\n\n private highlightText(str: string, search: any, className: string) {\n const searchTerm = search.trim()\n if (searchTerm === '') {\n return str\n }\n\n // Escape special regex characters in the search term to prevent regex injection\n const escapedSearch = searchTerm.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\n // Create a temporary div to parse HTML and work with text nodes only\n const tempDiv = document.createElement('div')\n tempDiv.innerHTML = str\n\n // Function to recursively process text nodes\n const highlightTextNodes = (node: Node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent || ''\n const regex = new RegExp('(' + escapedSearch + ')', 'i')\n\n if (regex.test(text)) {\n // Create a temporary container for the highlighted content\n const wrapper = document.createElement('span')\n const parts = text.split(regex)\n\n parts.forEach((part, index) => {\n if (part && regex.test(part)) {\n // This is the matched part - wrap it in mark\n const mark = document.createElement('mark')\n mark.className = className\n mark.textContent = part\n wrapper.appendChild(mark)\n } else if (part) {\n // This is not the matched part - keep as text\n wrapper.appendChild(document.createTextNode(part))\n }\n })\n\n // Replace the text node with the wrapper\n node.parentNode?.replaceChild(wrapper, node)\n }\n } else if (node.nodeType === Node.ELEMENT_NODE) {\n // Recursively process child nodes\n Array.from(node.childNodes).forEach((child) =>\n highlightTextNodes(child)\n )\n }\n }\n\n // Process all text nodes in the temporary div\n Array.from(tempDiv.childNodes).forEach((node) => highlightTextNodes(node))\n\n return tempDiv.innerHTML\n }\n\n private setContentDirection(direction: 'above' | 'below'): void {\n const isAbove = direction === 'above'\n const addClass = isAbove ? this.classes.dirAbove : this.classes.dirBelow\n const removeClass = isAbove ? this.classes.dirBelow : this.classes.dirAbove\n\n this.removeClasses(this.main.main, removeClass)\n this.addClasses(this.main.main, addClass)\n this.removeClasses(this.content.main, removeClass)\n this.addClasses(this.content.main, addClass)\n\n if (isAbove) {\n const mainHeight = this.main.main.offsetHeight\n const contentHeight = this.content.main.offsetHeight\n this.content.main.style.margin =\n '-' + (mainHeight + contentHeight - 1) + 'px 0px 0px 0px'\n } else {\n this.content.main.style.margin = '-1px 0px 0px 0px'\n }\n }\n\n private setContentPosition(): void {\n const containerRect = this.main.main.getBoundingClientRect()\n\n if (this.settings.contentPosition === 'relative') {\n this.applyContentWidth(containerRect)\n return\n }\n\n this.cancelOverflowShift()\n\n let top: number\n let left: number\n\n if (this.settings.contentPosition === 'fixed') {\n top = containerRect.top + containerRect.height\n left = containerRect.left\n } else {\n top = containerRect.top + window.scrollY + containerRect.height\n left = containerRect.left + window.scrollX\n }\n\n this.content.main.style.top = top + 'px'\n this.content.main.style.left = left + 'px'\n\n this.applyContentWidth(containerRect)\n\n const knownWidth = this.getKnownContentWidth(containerRect)\n if (knownWidth !== null) {\n this.content.main.style.left =\n this.adjustLeftForOverflow(left, containerRect.left, knownWidth) + 'px'\n return\n }\n\n // min/max/auto width needs one layout pass before measuring\n this.overflowShiftRaf = requestAnimationFrame(() => {\n this.overflowShiftRaf = 0\n this.applyOverflowShiftFromMeasure()\n })\n }\n\n private applyContentWidth(containerRect: DOMRect): void {\n const cw = this.settings.contentWidth\n this.content.main.style.width = ''\n this.content.main.style.minWidth = ''\n this.content.main.style.maxWidth = ''\n\n if (!cw) {\n if (this.settings.contentPosition !== 'relative') {\n this.content.main.style.width = containerRect.width + 'px'\n }\n return\n }\n\n if (cw.startsWith('>')) {\n this.content.main.style.minWidth = cw.slice(1)\n } else if (cw.startsWith('<')) {\n this.content.main.style.maxWidth = cw.slice(1)\n } else {\n this.content.main.style.width = cw\n }\n }\n\n private cancelOverflowShift(): void {\n if (this.overflowShiftRaf) {\n cancelAnimationFrame(this.overflowShiftRaf)\n this.overflowShiftRaf = 0\n }\n }\n\n /** Width in px when known before layout; null when width must be measured. */\n private getKnownContentWidth(containerRect: DOMRect): number | null {\n const cw = this.settings.contentWidth\n if (!cw) {\n return containerRect.width\n }\n if (cw.startsWith('>') || cw.startsWith('<') || cw.includes('%')) {\n return null\n }\n\n const px = parseFloat(cw)\n return Number.isNaN(px) ? null : px\n }\n\n private adjustLeftForOverflow(\n docLeft: number,\n viewportLeft: number,\n width: number\n ): number {\n const padding = 20\n const contentRight = viewportLeft + width\n if (contentRight <= window.innerWidth) {\n return docLeft\n }\n\n const overflow = contentRight - (window.innerWidth - padding)\n const newLeft = docLeft - overflow\n\n if (this.settings.contentPosition === 'fixed') {\n return Math.max(0, newLeft)\n }\n return Math.max(window.scrollX, newLeft)\n }\n\n private applyOverflowShiftFromMeasure(): void {\n const contentRect = this.content.main.getBoundingClientRect()\n const contentRight = contentRect.right\n if (contentRight <= window.innerWidth) {\n return\n }\n\n const padding = 20\n const overflow = contentRight - (window.innerWidth - padding)\n const currentLeft = parseFloat(this.content.main.style.left) || 0\n const newLeft = currentLeft - overflow\n\n if (this.settings.contentPosition === 'fixed') {\n this.content.main.style.left = Math.max(0, newLeft) + 'px'\n } else {\n this.content.main.style.left = Math.max(window.scrollX, newLeft) + 'px'\n }\n }\n\n public moveContentAbove(): void {\n this.setContentDirection('above')\n this.setContentPosition()\n }\n\n public moveContentBelow(): void {\n this.setContentDirection('below')\n this.setContentPosition()\n }\n\n public ensureElementInView(\n container: HTMLElement,\n element: HTMLElement\n ): void {\n const cTop = container.scrollTop + container.offsetTop\n const cBottom = cTop + container.clientHeight\n const eTop = element.offsetTop\n const eBottom = eTop + element.clientHeight\n\n if (eTop < cTop) {\n container.scrollTop -= cTop - eTop\n } else if (eBottom > cBottom) {\n container.scrollTop += eBottom - cBottom\n }\n }\n\n public putContent(): 'up' | 'down' {\n const mainHeight = this.main.main.offsetHeight\n const mainRect = this.main.main.getBoundingClientRect()\n const contentHeight = this.content.main.offsetHeight\n const spaceBelow = window.innerHeight - (mainRect.top + mainHeight)\n\n if (spaceBelow <= contentHeight) {\n if (mainRect.top > contentHeight) {\n return 'up'\n }\n return 'down'\n }\n\n return 'down'\n }\n\n // Updates deselect based on item count and allowDeselect setting\n public updateDeselectAll(): void {\n if (!this.store || !this.settings) {\n return\n }\n const selected = this.store.getSelectedOptions()\n const hasSelectedItems = selected && selected.length > 0\n const isMultiple = this.settings.isMultiple\n const allowDeselect = this.settings.allowDeselect\n const atMinSelected = this.isAtMinSelected()\n\n const deselectButton = this.main.deselect.main\n const hideClass = this.classes.hide\n\n if (\n allowDeselect &&\n !(isMultiple && !hasSelectedItems) &&\n !atMinSelected\n ) {\n this.removeClasses(deselectButton, hideClass)\n } else {\n this.addClasses(deselectButton, hideClass)\n }\n }\n}\n","/**\n * Pure classification of MutationObserver records on the native <select>.\n *\n * Select.observeCall() uses these flags to decide which sync path to run\n * (class/disabled vs full structure vs selection-only). Keeping this logic\n * separate makes it testable without spinning up a full SlimSelect instance.\n */\n\n/** What changed in a single observer callback batch (flags can all be true). */\nexport interface MutationFlags {\n /** Native select class attribute changed — sync to render styles only. */\n classChanged: boolean\n /** Native select disabled attribute changed — enable/disable SlimSelect. */\n disabledChanged: boolean\n /**\n * Options or optgroups were added, removed, or had attributes edited.\n * Triggers a full structure sync (store + native DOM + render).\n */\n optgroupOptionChanged: boolean\n /**\n * Selection may have changed without a separate `change` event yet.\n * Used when a newly added <option> is already the select's value.\n */\n selectionChanged: boolean\n}\n\n/**\n * Scan a MutationObserver batch and return which kinds of updates are needed.\n *\n * The observer watches the <select> with subtree: true, so mutations can\n * target the select itself or any child <option> / <optgroup>.\n */\nexport function classifyMutations(\n mutations: MutationRecord[],\n select: HTMLSelectElement\n): MutationFlags {\n const flags: MutationFlags = {\n classChanged: false,\n disabledChanged: false,\n optgroupOptionChanged: false,\n selectionChanged: false\n }\n\n for (const m of mutations) {\n // Mutations directly on the <select> element\n if (m.target === select) {\n if (m.attributeName === 'disabled') {\n flags.disabledChanged = true\n }\n\n if (m.attributeName === 'class') {\n flags.classChanged = true\n }\n\n if (m.type === 'childList') {\n // Detect \"add option and it becomes selected\" in one DOM update\n // (e.g. appendChild + select.value = 'x'). Without this, we'd only\n // run structure sync and miss that selection also changed.\n for (const n of Array.from(m.addedNodes)) {\n if (\n n.nodeName === 'OPTION' &&\n (n as HTMLOptionElement).value === select.value\n ) {\n flags.selectionChanged = true\n break\n }\n }\n\n // Any childList on the select means options were added/removed/replaced\n flags.optgroupOptionChanged = true\n }\n }\n\n // Attribute edits on options (selected, text, data-*) or optgroup changes\n // bubble up as mutations on child nodes, not on the select itself\n if (m.target.nodeName === 'OPTGROUP' || m.target.nodeName === 'OPTION') {\n flags.optgroupOptionChanged = true\n }\n }\n\n return flags\n}\n","import { copyOptionData, kebabCase, hasClassInTree } from './helpers'\nimport { classifyMutations } from './mutations'\nimport { Optgroup, Option } from './store'\n\nexport default class Select {\n public select: HTMLSelectElement\n\n // Mutation observer fields\n public onValueChange?: (value: Option[]) => void\n public onClassChange?: (classes: string[]) => void\n public onDisabledChange?: (disabled: boolean) => void\n public onOptionsChange?: (data: (Option | Optgroup)[]) => void\n public onLabelClick?: () => void\n\n // Change observers\n private listen: boolean = false\n private observer: MutationObserver | null = null\n private isUpdating: boolean = false\n private pendingOptionsChange: (Option | Optgroup)[] | null = null\n\n // Event handlers for preventing native select behavior (especially on iOS Safari)\n private preventNativeSelect: ((e: Event) => void) | null = null\n private preventNativeSelectMousedown: ((e: Event) => void) | null = null\n private preventNativeSelectFocus: ((e: Event) => void) | null = null\n private restoreAriaHiddenOnBlur: ((e: Event) => void) | null = null\n\n constructor(select: HTMLSelectElement) {\n this.select = select\n\n this.valueChange = this.valueChange.bind(this)\n // Add change event listener\n this.select.addEventListener('change', this.valueChange, {\n // allow bubbling of event\n passive: true\n })\n\n // Initiate mutation observer\n this.observer = new MutationObserver(this.observeCall.bind(this))\n\n // Start listening for changes\n this.changeListen(true)\n }\n\n public enable(): void {\n this.select.disabled = false\n }\n\n public disable(): void {\n this.select.disabled = true\n }\n\n public hideUI(): void {\n this.select.tabIndex = -1\n // Visually hide but keep focusable for form validation\n // Use 1px dimensions so browser validation popup can display\n this.select.style.position = 'absolute'\n this.select.style.width = '1px'\n this.select.style.height = '1px'\n this.select.style.opacity = '0'\n this.select.style.overflow = 'hidden'\n this.select.style.pointerEvents = 'none'\n // Remove any spacing or borders that could affect layout\n this.select.style.margin = '0'\n this.select.style.padding = '0'\n this.select.style.borderWidth = '0'\n // Clip to completely hide the 1px\n this.select.style.clipPath = 'inset(50%)'\n // Only apply aria-hidden if the select doesn't currently hold focus.\n // Browsers (Chrome) block aria-hidden on a focused element and log a\n // warning, since focus must not be hidden from assistive technology.\n // If the select is focused right now, the blur handler below will\n // apply aria-hidden once focus leaves the element.\n if (document.activeElement !== this.select) {\n this.select.setAttribute('aria-hidden', 'true')\n }\n\n // Prevent native select from opening when label is clicked (especially on iOS Safari)\n // iOS Safari programmatically focuses/clicks the select when label is clicked,\n // bypassing pointer-events: none, so we need to prevent these events\n // Only add listeners if they haven't been added yet\n if (!this.preventNativeSelect) {\n this.preventNativeSelect = (e: Event) => {\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n }\n\n this.preventNativeSelectMousedown = (e: Event) => {\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n }\n\n this.preventNativeSelectFocus = (e: Event) => {\n // Focus events are not cancelable, so the select may still end up\n // focused (e.g. the browser focusing an invalid control during form\n // validation, or a programmatic select.focus() call). Lift aria-hidden\n // while the element holds focus so assistive technology isn't blocked\n // from it; it gets restored by the blur handler.\n this.select.removeAttribute('aria-hidden')\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n }\n\n // Re-apply aria-hidden once focus leaves the hidden select\n this.restoreAriaHiddenOnBlur = () => {\n this.select.setAttribute('aria-hidden', 'true')\n }\n\n // Add event listeners with capture phase to catch events before they reach the select\n this.select.addEventListener('click', this.preventNativeSelect, {\n capture: true,\n passive: false\n })\n this.select.addEventListener(\n 'mousedown',\n this.preventNativeSelectMousedown,\n { capture: true, passive: false }\n )\n this.select.addEventListener('focus', this.preventNativeSelectFocus, {\n capture: true,\n passive: false\n })\n this.select.addEventListener('blur', this.restoreAriaHiddenOnBlur, {\n capture: true,\n passive: true\n })\n }\n }\n\n public showUI(): void {\n this.select.removeAttribute('tabindex')\n // Reset visual hiding styles\n this.select.style.position = ''\n this.select.style.width = ''\n this.select.style.height = ''\n this.select.style.opacity = ''\n this.select.style.overflow = ''\n this.select.style.pointerEvents = ''\n this.select.style.margin = ''\n this.select.style.padding = ''\n this.select.style.borderWidth = ''\n this.select.style.clipPath = ''\n this.select.removeAttribute('aria-hidden')\n\n // Remove event listeners that prevent native select behavior\n if (this.preventNativeSelect) {\n this.select.removeEventListener('click', this.preventNativeSelect, {\n capture: true\n })\n this.preventNativeSelect = null\n }\n if (this.preventNativeSelectMousedown) {\n this.select.removeEventListener(\n 'mousedown',\n this.preventNativeSelectMousedown,\n { capture: true }\n )\n this.preventNativeSelectMousedown = null\n }\n if (this.preventNativeSelectFocus) {\n this.select.removeEventListener('focus', this.preventNativeSelectFocus, {\n capture: true\n })\n this.preventNativeSelectFocus = null\n }\n if (this.restoreAriaHiddenOnBlur) {\n this.select.removeEventListener('blur', this.restoreAriaHiddenOnBlur, {\n capture: true\n })\n this.restoreAriaHiddenOnBlur = null\n }\n }\n\n public changeListen(listen: boolean) {\n this.listen = listen\n\n // Start listening for changes\n if (listen) {\n if (this.observer) {\n this.observer.observe(this.select, {\n subtree: true, // subtree for optgroups options\n childList: true, // children changes\n attributes: true // attributes changes\n })\n }\n }\n\n // Stop listening for changes\n if (!listen) {\n if (this.observer) {\n this.observer.disconnect()\n }\n }\n }\n\n // This function get triggers when the select value changes\n // and will call the onValueChange function if it exists\n public valueChange(ev: Event): boolean {\n if (this.listen && this.onValueChange) {\n this.onValueChange(this.getSelectedOptions())\n }\n\n // Allow bubbling back to other change event listeners\n return true\n }\n\n private observeCall(mutations: MutationRecord[]): void {\n // If we are not listening, do nothing.\n if (!this.listen) {\n return\n }\n\n // Pure classifier — separates class/disabled/structure/selection mutations\n const {\n classChanged,\n disabledChanged,\n optgroupOptionChanged,\n selectionChanged: initialSelectionChanged\n } = classifyMutations(mutations, this.select)\n let selectionChanged = initialSelectionChanged\n\n // If class has changed then call the class change function\n if (classChanged && this.onClassChange) {\n this.onClassChange(this.select.className.split(' '))\n }\n\n // If disabled has changed then call the disabled change function\n if (disabledChanged && this.onDisabledChange) {\n this.changeListen(false)\n this.onDisabledChange(this.select.disabled)\n this.changeListen(true)\n }\n\n // If optgroup or option has changed then call the select change function\n if (optgroupOptionChanged && this.onOptionsChange) {\n // If we're currently updating, queue this change to process after update completes\n if (this.isUpdating) {\n // Only queue if the select element actually has options (not empty from updateOptions clearing)\n // Check the select element directly, not getData() which might return stale data\n if (this.select.options.length > 0) {\n const currentData = this.getData()\n // Only queue if we have actual data\n if (currentData.length > 0) {\n this.pendingOptionsChange = currentData\n }\n }\n if (selectionChanged) {\n this.select.dispatchEvent(new Event('change'))\n }\n return\n }\n\n this.changeListen(false)\n this.onOptionsChange(this.getData())\n this.changeListen(true)\n\n // Structure sync includes selection from getData(); skip redundant change event\n selectionChanged = false\n }\n\n if (selectionChanged) {\n this.select.dispatchEvent(new Event('change'))\n }\n }\n\n // From the select element pull optgroup and options into data\n public getData(): (Option | Optgroup)[] {\n let data = []\n\n // Loop through nodes and get data\n const nodes = this.select.childNodes as any as\n | HTMLOptGroupElement[]\n | HTMLOptionElement[]\n for (const n of nodes) {\n // Optgroup\n if (n.nodeName === 'OPTGROUP') {\n data.push(this.getDataFromOptgroup(n as HTMLOptGroupElement))\n }\n\n // Option\n if (n.nodeName === 'OPTION') {\n data.push(this.getDataFromOption(n as HTMLOptionElement))\n }\n }\n\n return data\n }\n\n public getDataFromOptgroup(optgroup: HTMLOptGroupElement): Optgroup {\n let data = {\n id: optgroup.id,\n label: optgroup.label,\n selectAll: optgroup.dataset\n ? optgroup.dataset.selectall === 'true'\n : false,\n closable: optgroup.dataset ? optgroup.dataset.closable : 'off',\n options: []\n } as Optgroup\n\n const options = optgroup.childNodes as any as HTMLOptionElement[]\n for (const o of options) {\n if (o.nodeName === 'OPTION') {\n data.options!.push(this.getDataFromOption(o as HTMLOptionElement))\n }\n }\n\n return data\n }\n\n // From passed in option pull pieces of usable information\n public getDataFromOption(option: HTMLOptionElement): Option {\n return {\n id: option.id,\n value: option.value,\n text: option.text,\n html: option.dataset && option.dataset.html ? option.dataset.html : '',\n defaultSelected: option.defaultSelected,\n selected: option.selected,\n display: option.style.display !== 'none',\n disabled: option.disabled,\n mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,\n placeholder: option.dataset.placeholder === 'true',\n class: option.className,\n style: option.style.cssText,\n data: copyOptionData(option.dataset)\n } as Option\n }\n\n public getSelectedOptions(): Option[] {\n let options = []\n\n // Loop through options and set selected\n const opts = this.select.childNodes as any as (\n | HTMLOptGroupElement\n | HTMLOptionElement\n )[]\n for (const o of opts) {\n if (o.nodeName === 'OPTGROUP') {\n const optgroupOptions = o.childNodes as any as HTMLOptionElement[]\n for (const oo of optgroupOptions) {\n if (oo.nodeName === 'OPTION') {\n const option = oo as HTMLOptionElement\n if (option.selected) {\n options.push(this.getDataFromOption(option))\n }\n }\n }\n }\n\n if (o.nodeName === 'OPTION') {\n const option = o as HTMLOptionElement\n if (option.selected) {\n options.push(this.getDataFromOption(option))\n }\n }\n }\n\n return options\n }\n\n public getSelectedValues(): string[] {\n return this.getSelectedOptions().map((option) => option.value)\n }\n\n public setSelected(ids: string[]): void {\n // Stop listening to changes\n this.changeListen(false)\n\n // Loop through options and set selected\n const options = this.select.childNodes as any as (\n | HTMLOptGroupElement\n | HTMLOptionElement\n )[]\n for (const o of options) {\n if (o.nodeName === 'OPTGROUP') {\n const optgroup = o as HTMLOptGroupElement\n const optgroupOptions =\n optgroup.childNodes as any as HTMLOptionElement[]\n for (const oo of optgroupOptions) {\n if (oo.nodeName === 'OPTION') {\n const option = oo as HTMLOptionElement\n option.selected = ids.includes(option.id)\n }\n }\n }\n\n if (o.nodeName === 'OPTION') {\n const option = o as HTMLOptionElement\n option.selected = ids.includes(option.id)\n }\n }\n\n // Keep native value in sync for form validation and parent bindings\n const selected = this.getSelectedOptions()\n if (!this.select.multiple) {\n this.select.value = selected.length === 1 ? selected[0].value : ''\n }\n\n // Fire native change listeners while observer is paused to avoid re-entrant sync\n this.select.dispatchEvent(new Event('change', { bubbles: true }))\n\n this.changeListen(true)\n }\n\n // Set selected options by value instead of id.\n // SyncCoordinator uses this path — HTML option ids are often empty.\n // This is useful when the id is not known\n // and only the value is known\n // but the value is not unique and can be duplicated\n public setSelectedByValue(values: string[]): void {\n // Stop listening to changes\n this.changeListen(false)\n\n // Loop through options and set selected\n const options = this.select.childNodes as any as (\n | HTMLOptGroupElement\n | HTMLOptionElement\n )[]\n for (const o of options) {\n if (o.nodeName === 'OPTGROUP') {\n const optgroup = o as HTMLOptGroupElement\n const optgroupOptions =\n optgroup.childNodes as any as HTMLOptionElement[]\n for (const oo of optgroupOptions) {\n if (oo.nodeName === 'OPTION') {\n const option = oo as HTMLOptionElement\n option.selected = values.includes(option.value)\n }\n }\n }\n\n if (o.nodeName === 'OPTION') {\n const option = o as HTMLOptionElement\n option.selected = values.includes(option.value)\n }\n }\n\n const selected = this.getSelectedOptions()\n if (!this.select.multiple) {\n // Sync native value for form validation / Vue v-model\n this.select.value = selected.length === 1 ? selected[0].value : ''\n }\n\n // Fire native change listeners while observer is paused to avoid re-entrant sync\n this.select.dispatchEvent(new Event('change', { bubbles: true }))\n\n this.changeListen(true)\n }\n\n public updateSelect(id?: string, style?: string, classes?: string[]): void {\n // Stop listening to changes\n this.changeListen(false)\n\n // Update id, only if the id isnt already set\n if (id) {\n this.select.dataset.id = id\n }\n\n // Update style\n if (style) {\n this.select.style.cssText = style\n }\n\n // Update classes\n if (classes) {\n this.select.className = ''\n classes.forEach((c) => {\n if (c.trim() !== '') {\n this.select.classList.add(c.trim())\n }\n })\n }\n\n // Start listening to changes\n this.changeListen(true)\n }\n\n public updateOptions(data: (Option | Optgroup)[]): void {\n // Don't update if data is empty (prevents clearing select when no data)\n if (!data || data.length === 0) {\n return\n }\n\n // Set updating flag FIRST to prevent mutation observer from processing during update\n // This must be set before stopping listening so any queued mutations see the flag\n this.isUpdating = true\n this.pendingOptionsChange = null\n\n // Stop listening to changes\n this.changeListen(false)\n\n // Clear out select\n this.select.innerHTML = ''\n\n for (const d of data) {\n if (d instanceof Optgroup) {\n this.select.appendChild(this.createOptgroup(d))\n }\n\n if (d instanceof Option) {\n this.select.appendChild(this.createOption(d))\n }\n }\n\n // Trigger change event on original select\n this.select.dispatchEvent(new Event('change', { bubbles: true }))\n\n // Start listening to changes\n this.changeListen(true)\n\n // Clear updating flag\n this.isUpdating = false\n\n // Process any pending options change that was queued during the update\n // Only process if it has data (don't process empty data from innerHTML clearing)\n if (this.pendingOptionsChange !== null) {\n const pending: (Option | Optgroup)[] = this.pendingOptionsChange\n if (pending.length > 0 && this.onOptionsChange) {\n this.pendingOptionsChange = null\n // Process the queued change\n this.changeListen(false)\n this.onOptionsChange(pending)\n this.changeListen(true)\n } else {\n // Clear pending if it was empty\n this.pendingOptionsChange = null\n }\n }\n }\n\n public createOptgroup(optgroup: Optgroup): HTMLOptGroupElement {\n const optgroupEl = document.createElement('optgroup')\n optgroupEl.id = optgroup.id\n optgroupEl.label = optgroup.label\n if (optgroup.selectAll) {\n optgroupEl.dataset.selectAll = 'true'\n }\n if (optgroup.closable !== 'off') {\n optgroupEl.dataset.closable = optgroup.closable\n }\n if (optgroup.options) {\n for (const option of optgroup.options) {\n optgroupEl.appendChild(this.createOption(option as Option))\n }\n }\n return optgroupEl\n }\n\n public createOption(info: Option): HTMLOptionElement {\n const optionEl = document.createElement('option')\n optionEl.id = info.id\n optionEl.value = info.value\n optionEl.textContent = info.text\n if (info.html !== '') {\n optionEl.setAttribute('data-html', info.html)\n }\n optionEl.defaultSelected = info.defaultSelected\n optionEl.selected = info.selected // Explicitly set selected because defaultSelected: true sets selected to true\n if (info.disabled) {\n optionEl.disabled = true\n }\n if (!info.display) {\n optionEl.style.display = 'none'\n }\n if (info.placeholder) {\n optionEl.setAttribute('data-placeholder', 'true')\n }\n if (info.mandatory) {\n optionEl.setAttribute('data-mandatory', 'true')\n }\n if (info.class) {\n info.class.split(' ').forEach((optionClass: string) => {\n optionEl.classList.add(optionClass)\n })\n }\n if (info.data && typeof info.data === 'object') {\n Object.keys(info.data).forEach((key) => {\n optionEl.setAttribute('data-' + kebabCase(key), info.data[key])\n })\n }\n\n return optionEl\n }\n\n // Find and handle labels associated with this select\n public setupLabelHandlers(): void {\n const labels: HTMLLabelElement[] = []\n\n // Find labels that point to this select via 'for' attribute\n const selectId = this.select.id\n if (selectId) {\n const labelsByFor = document.querySelectorAll<HTMLLabelElement>(\n `label[for=\"${selectId}\"]`\n )\n labelsByFor.forEach((label) => labels.push(label))\n }\n\n // Find labels that wrap this select (label contains select)\n let parent = this.select.parentElement\n while (parent && parent !== document.body) {\n if (parent.tagName === 'LABEL') {\n labels.push(parent as HTMLLabelElement)\n break\n }\n parent = parent.parentElement\n }\n\n // Remove duplicates\n const uniqueLabels = Array.from(new Set(labels))\n\n uniqueLabels.forEach((label) => {\n // Skip if already handled\n if ((label as any).__slimSelectLabelHandler) {\n return\n }\n\n // Add click handler to label\n const labelClickHandler = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n\n // Check if click is on SlimSelect UI elements (main div or content)\n const isSlimSelectElement = hasClassInTree(\n target,\n this.select.dataset.id!\n )\n\n // Prevent default label behavior (focusing the select)\n // This needs to happen for all clicks on the label or its children\n // to prevent the browser from focusing the hidden select\n e.preventDefault()\n // e.stopPropagation() // dont stop propagation\n\n // Only trigger the toggle if the click is NOT on SlimSelect elements\n // This allows clicking label text/children to toggle, while wrapped SlimSelect handles its own clicks\n if (!isSlimSelectElement && this.onLabelClick) {\n this.onLabelClick()\n }\n }\n\n // Store the handler on the label for cleanup later\n ;(label as any).__slimSelectLabelHandler = labelClickHandler\n label.addEventListener('click', labelClickHandler, {\n capture: true,\n passive: false\n })\n })\n }\n\n // Remove label handlers\n public removeLabelHandlers(): void {\n const labels: HTMLLabelElement[] = []\n\n // Find labels that point to this select via 'for' attribute\n const selectId = this.select.id\n if (selectId) {\n const labelsByFor = document.querySelectorAll<HTMLLabelElement>(\n `label[for=\"${selectId}\"]`\n )\n labelsByFor.forEach((label) => labels.push(label))\n }\n\n // Find labels that wrap this select\n let parent = this.select.parentElement\n while (parent && parent !== document.body) {\n if (parent.tagName === 'LABEL') {\n labels.push(parent as HTMLLabelElement)\n break\n }\n parent = parent.parentElement\n }\n\n // Remove duplicates\n const uniqueLabels = Array.from(new Set(labels))\n\n uniqueLabels.forEach((label) => {\n const handler = (label as any).__slimSelectLabelHandler\n if (handler) {\n label.removeEventListener('click', handler, { capture: true })\n delete (label as any).__slimSelectLabelHandler\n }\n })\n }\n\n public destroy() {\n this.changeListen(false)\n\n // Remove event change listener\n this.select.removeEventListener('change', this.valueChange)\n\n // Remove event listeners that prevent native select behavior\n if (this.preventNativeSelect) {\n this.select.removeEventListener('click', this.preventNativeSelect, {\n capture: true\n })\n this.preventNativeSelect = null\n }\n if (this.preventNativeSelectMousedown) {\n this.select.removeEventListener(\n 'mousedown',\n this.preventNativeSelectMousedown,\n { capture: true }\n )\n this.preventNativeSelectMousedown = null\n }\n if (this.preventNativeSelectFocus) {\n this.select.removeEventListener('focus', this.preventNativeSelectFocus, {\n capture: true\n })\n this.preventNativeSelectFocus = null\n }\n if (this.restoreAriaHiddenOnBlur) {\n this.select.removeEventListener('blur', this.restoreAriaHiddenOnBlur, {\n capture: true\n })\n this.restoreAriaHiddenOnBlur = null\n }\n\n // Disconnect observer and null\n if (this.observer) {\n this.observer.disconnect()\n this.observer = null\n }\n\n // Remove label handlers\n this.removeLabelHandlers()\n\n // Remove dataset id from original select\n delete this.select.dataset.id\n\n // Show the original select\n this.showUI()\n }\n}\n","/**\n * Central sync pipeline for SlimSelect.\n *\n * All paths that change store, native <select>, or custom UI should go through\n * SyncCoordinator instead of calling setData/setSelected directly. This gives us:\n * - One place to batch/coalesce updates\n * - Lightweight selection sync (no full native DOM rebuild)\n * - No-op skips when nothing actually changed\n *\n * Wired from SlimSelect: native observer → enqueue(native), public API → enqueue(api),\n * render callbacks → enqueue(ui).\n */\n\nimport Render from './render'\nimport Select from './select'\nimport Store, { Optgroup, Option } from './store'\nimport { dataStructureEqual, selectedIdsEqual } from './helpers'\n\n/** Where a change originated — affects batching and render behavior. */\nexport type ChangeSource = 'native' | 'ui' | 'api'\n\nexport interface SyncEvents {\n afterChange?: (newVal: Option[]) => void\n error?: (err: Error) => void\n}\n\n/**\n * A single unit of work in the sync queue.\n * Structure = replace option list; selection = change selected only; addOption = append one.\n */\nexport type SyncChange =\n | {\n type: 'structure'\n data: (Partial<Option> | Partial<Optgroup>)[]\n source: ChangeSource\n /** Keep current selection when replacing data (async search results). */\n preserveSelection?: boolean\n /** API search results — do not update the catalog baseline. */\n isSearchResult?: boolean\n }\n | {\n type: 'selection'\n values: string | string[]\n source: ChangeSource\n /** false when Vue/parent is pushing modelValue down (avoid emit loop). */\n runAfterChange?: boolean\n }\n | { type: 'addOption'; option: Partial<Option>; source: ChangeSource }\n\nexport interface SyncDeps {\n select: Select\n store: Store\n render: Render\n events: SyncEvents\n search?: (value: string) => void\n onError?: (err: Error) => void\n}\n\n/** Skip structure sync when incoming data matches what's already in the store. */\nexport function shouldSkipStructureUpdate(\n store: Store,\n data: (Partial<Option> | Partial<Optgroup>)[]\n): boolean {\n return dataStructureEqual(store.getData(false), data)\n}\n\n/**\n * Resolve setSelected() arguments to option ids.\n * Accepts either ids or values for backward compatibility.\n */\nexport function resolveSelectedIds(\n store: Store,\n values: string | string[]\n): string[] {\n const valueList = Array.isArray(values) ? values : [values]\n const options = store.getDataOptions(false)\n const ids: string[] = []\n\n for (const value of valueList) {\n if (options.find((option) => option.id == value)) {\n ids.push(value)\n continue\n }\n\n // Value may match multiple options (duplicate values) — select all matches\n for (const option of options.filter((option) => option.value == value)) {\n ids.push(option.id)\n }\n }\n\n return ids\n}\n\nexport default class SyncCoordinator {\n private queue: SyncChange[] = []\n private flushScheduled = false\n /** True while applyChange is running — prevents re-entrant flush loops. */\n public isSyncing = false\n\n constructor(private deps: SyncDeps) {}\n\n public enqueue(change: SyncChange): void {\n this.queue.push(change)\n\n // Native mutations often arrive in bursts from MutationObserver; coalesce\n // them in one microtask so we render once per frame.\n if (change.source === 'native') {\n if (!this.flushScheduled) {\n this.flushScheduled = true\n queueMicrotask(() => this.flush())\n }\n return\n }\n\n // API/UI (setData, setSelected, clicks) should feel instant to callers.\n // If we're already inside flush(), defer until the current batch finishes.\n if (!this.isSyncing) {\n this.flush()\n }\n }\n\n /** Process everything in the queue. Callable from tests for deterministic native sync. */\n public flush(): void {\n this.flushScheduled = false\n\n if (this.queue.length === 0) {\n return\n }\n\n const batch = this.coalesceBatch(this.queue)\n this.queue = []\n\n this.isSyncing = true\n try {\n for (const change of batch) {\n this.applyChange(change)\n }\n } finally {\n this.isSyncing = false\n // Changes enqueued during applyChange (e.g. async search) run next\n if (this.queue.length > 0) {\n this.flush()\n }\n }\n }\n\n /**\n * Collapse a batch into the minimum work needed.\n * Structure sync already includes selection from getData(), so drop redundant\n * selection changes in the same batch. When multiple structure updates arrive,\n * only the last one wins.\n */\n private coalesceBatch(changes: SyncChange[]): SyncChange[] {\n const hasStructure = changes.some((c) => c.type === 'structure')\n const hasAddOption = changes.some((c) => c.type === 'addOption')\n\n if (hasStructure || hasAddOption) {\n const structureChanges = changes.filter(\n (c) => c.type === 'structure' || c.type === 'addOption'\n )\n const lastStructure = structureChanges[structureChanges.length - 1]\n\n if (lastStructure?.type === 'structure') {\n return [lastStructure]\n }\n\n return structureChanges\n }\n\n const selectionChanges = changes.filter((c) => c.type === 'selection')\n if (selectionChanges.length > 0) {\n return [selectionChanges[selectionChanges.length - 1]]\n }\n\n return changes\n }\n\n private applyChange(change: SyncChange): void {\n switch (change.type) {\n case 'structure':\n this.applyStructure(\n change.data,\n change.source,\n change.preserveSelection,\n change.isSearchResult\n )\n break\n case 'selection':\n this.applySelection(\n change.values,\n change.source,\n change.runAfterChange !== false\n )\n break\n case 'addOption':\n this.applyAddOption(change.option)\n break\n }\n }\n\n /**\n * Full sync: store → native <select> rebuild → render values + options.\n * Used when the option list itself changes (setData, native DOM edits, search results).\n */\n private applyStructure(\n data: (Partial<Option> | Partial<Optgroup>)[],\n _source: ChangeSource,\n preserveSelection = false,\n isSearchResult = false\n ): void {\n const { store, select, render, events } = this.deps\n\n // API search always shows \"Searching...\" first — even when results match the\n // current store, we must re-render so that placeholder is cleared (#695).\n if (!isSearchResult && shouldSkipStructureUpdate(store, data)) {\n return\n }\n\n const selected = store.getSelected()\n\n const err = store.validateDataArray(data)\n if (err) {\n if (events.error) {\n events.error(err)\n } else if (this.deps.onError) {\n this.deps.onError(err)\n }\n return\n }\n\n store.setData(data, preserveSelection)\n const dataClean = store.getData(false)\n\n if (!isSearchResult) {\n store.snapshotCatalog()\n }\n\n select.updateOptions(dataClean)\n render.renderValues()\n render.renderOptions(dataClean)\n\n if (events.afterChange && !selectedIdsEqual(selected, store.getSelected())) {\n events.afterChange(store.getSelectedOptions())\n }\n }\n\n /**\n * Lightweight selection sync: flip option.selected on native DOM only.\n * Avoids select.updateOptions() (innerHTML rebuild) for selection-only changes.\n */\n private applySelection(\n values: string | string[],\n _source: ChangeSource,\n runAfterChange: boolean\n ): void {\n const { store, select, render, events } = this.deps\n\n const selected = store.getSelected()\n const ids = resolveSelectedIds(store, values)\n\n if (selectedIdsEqual(selected, ids)) {\n return\n }\n\n store.setSelectedBy('id', ids)\n\n // Use values on the native DOM — HTML option ids may be empty while store uses generated ids\n select.setSelectedByValue(store.getSelectedValues())\n render.renderValues()\n\n const searchValue = render.content.search.input.value.trim()\n if (searchValue !== '') {\n if (render.hasRenderedOptions()) {\n render.updateOptionSelection()\n } else if (this.deps.search) {\n this.deps.search(searchValue)\n }\n } else if (render.canUpdateOptionSelectionInPlace()) {\n render.updateOptionSelection()\n } else {\n render.renderOptions(store.getData(false))\n }\n\n if (\n runAfterChange &&\n events.afterChange &&\n !selectedIdsEqual(selected, store.getSelected())\n ) {\n events.afterChange(store.getSelectedOptions())\n }\n }\n\n /** Append a single option then full-sync native + render (same as legacy addOption). */\n private applyAddOption(option: Partial<Option>): void {\n const { store, select, render, events } = this.deps\n const selected = store.getSelected()\n const searchValue = render.content.search.input.value.trim()\n const isApiSearchOverlay = searchValue !== '' && !!this.deps.search\n const optionValue = option.value ?? option.text ?? ''\n\n const optionExists = (data: (Option | Optgroup)[]): boolean => {\n for (const item of data) {\n if (item instanceof Optgroup) {\n if (\n item.options.some((opt) => (opt.value ?? opt.text) === optionValue)\n ) {\n return true\n }\n continue\n }\n\n if ((item.value ?? item.text) === optionValue) {\n return true\n }\n }\n\n return false\n }\n\n if (!optionExists(store.getData(false))) {\n if (isApiSearchOverlay) {\n const baseline = store.getCatalogData()\n if (!optionExists(baseline)) {\n store.setData([...baseline, new Option(option)], true)\n }\n store.snapshotCatalog()\n } else {\n store.addOption(option)\n store.snapshotCatalog()\n }\n }\n\n const data = store.getData(false)\n select.updateOptions(data)\n render.renderValues()\n render.renderOptions(data)\n\n if (events.afterChange && !selectedIdsEqual(selected, store.getSelected())) {\n events.afterChange(store.getSelectedOptions())\n }\n }\n}\n","import CssClasses from './classes'\nimport { getAnimationTimeout } from './animations'\nimport GlobalEvents, { hasClassInTree } from './events'\nimport { debounce, getAssociatedLabelText } from './helpers'\nimport Lifecycle from './lifecycle'\nimport Render, { CloseInfo } from './render'\nimport Select from './select'\nimport Settings, { MODAL_MOBILE_BREAKPOINT } from './settings'\nimport Store, { Option, Optgroup } from './store'\nimport SyncCoordinator from './sync'\n\n// Export classes\nexport { Settings, Option, Optgroup, MODAL_MOBILE_BREAKPOINT }\nexport type { ModalSetting } from './settings'\n\n// Export interfaces from render\nexport type { Main, Content, Search, CloseInfo, CloseSource } from './render'\n\nexport interface Config {\n select: string | Element\n data?: (Partial<Option> | Partial<Optgroup>)[]\n settings?: Partial<Settings>\n cssClasses?: Partial<CssClasses>\n events?: Events\n}\n\nexport interface Events {\n search?: (\n searchValue: string,\n selected: Option[],\n catalog?: (Option | Optgroup)[]\n ) =>\n | Promise<(Partial<Option> | Partial<Optgroup>)[]>\n | (Partial<Option> | Partial<Optgroup>)[]\n searchFilter?: (option: Option, search: string) => boolean\n addable?: (\n value: string\n ) =>\n | Promise<Partial<Option> | string>\n | Partial<Option>\n | string\n | false\n | null\n | undefined\n | Error\n beforeChange?: (newVal: Option[], oldVal: Option[]) => boolean | void\n afterChange?: (newVal: Option[]) => void\n beforeOpen?: () => void\n afterOpen?: () => void\n beforeClose?: (info: CloseInfo) => boolean | void\n afterClose?: () => void\n error?: (err: Error) => void\n}\n\nexport default class SlimSelect {\n public selectEl: HTMLSelectElement\n\n // Classes\n public settings!: Settings\n public cssClasses!: CssClasses\n public select!: Select\n public store!: Store\n public render!: Render\n public sync!: SyncCoordinator\n public lifecycle!: Lifecycle\n private globalEvents!: GlobalEvents\n /** Invalidates in-flight API search responses when the query changes or clears. */\n private searchGeneration = 0\n\n // Events\n public events = {\n search: undefined,\n searchFilter: (opt: Option, search: string) => {\n return opt.text.toLowerCase().indexOf(search.toLowerCase()) !== -1\n },\n addable: undefined,\n beforeChange: undefined,\n afterChange: undefined,\n beforeOpen: undefined,\n afterOpen: undefined,\n beforeClose: undefined,\n afterClose: undefined\n } as Events\n\n constructor(config: Config) {\n // Make sure you get the right element\n this.selectEl = (\n typeof config.select === 'string'\n ? document.querySelector(config.select)\n : config.select\n ) as HTMLSelectElement\n if (!this.selectEl) {\n if (config.events && config.events.error) {\n config.events.error(new Error('Could not find select element'))\n }\n return\n }\n if (this.selectEl.tagName !== 'SELECT') {\n if (config.events && config.events.error) {\n config.events.error(new Error('Element isnt of type select'))\n }\n return\n }\n\n // If select already has a slim select id on it lets destroy it first\n if (this.selectEl.dataset.ssid) {\n this.destroy()\n }\n\n // Set settings\n this.settings = new Settings(config.settings)\n\n // Set CSS classes\n this.cssClasses = new CssClasses(config.cssClasses)\n\n // Set events\n const debounceEvents = ['beforeOpen', 'afterOpen', 'afterClose']\n for (const key in config.events) {\n // Check if key exists in events\n if (!config.events.hasOwnProperty(key)) {\n continue\n }\n\n // Check if key is in debounceEvents\n if (debounceEvents.indexOf(key) !== -1) {\n ;(this.events as { [key: string]: any })[key] = debounce(\n (config.events as { [key: string]: any })[key],\n 100\n )\n } else {\n ;(this.events as { [key: string]: any })[key] = (\n config.events as { [key: string]: any }\n )[key]\n }\n }\n\n // Upate settings with type, style and classname\n this.settings.disabled = config.settings?.disabled\n ? config.settings.disabled\n : this.selectEl.disabled\n this.settings.isMultiple = this.selectEl.multiple\n this.settings.style = this.selectEl.style.cssText\n this.settings.class = this.selectEl.className.split(' ')\n\n // Set select class\n this.select = new Select(this.selectEl)\n // Ensure the select has an id for label associations\n if (!this.selectEl.id) {\n this.selectEl.id = this.settings.id\n }\n this.select.updateSelect(\n this.settings.id,\n this.settings.style,\n this.settings.class\n )\n this.select.hideUI() // Hide the original select element\n\n this.select.onClassChange = (classes: string[]) => {\n // Update settings with new class\n this.settings.class = classes\n\n // Run render updateClassStyles\n this.render.updateClassStyles()\n }\n this.select.onDisabledChange = (disabled: boolean) => {\n if (disabled) {\n this.disable()\n } else {\n this.enable()\n }\n }\n\n // Set up label click handler to toggle SlimSelect\n // This allows clicking the label to open/close, matching the main div behavior\n this.select.onLabelClick = () => {\n if (!this.settings.disabled) {\n this.settings.isOpen\n ? this.close({ source: 'toggle', selectionChanged: false })\n : this.open()\n }\n }\n\n // Set store class\n const data = config.data ? config.data : this.select.getData()\n this.store = new Store(\n this.settings.isMultiple ? 'multiple' : 'single',\n data\n )\n\n // If data is passed update the original select element\n if (config.data) {\n this.select.updateOptions(this.store.getData())\n }\n\n // Set render renderCallbacks\n const renderCallbacks = {\n open: this.open.bind(this),\n close: this.close.bind(this),\n addable: this.events.addable ? this.events.addable : undefined,\n // UI clicks route through SyncCoordinator (batched, avoids double updates)\n setSelected: (values: string | string[], runAfterChange: boolean) => {\n this.sync.enqueue({\n type: 'selection',\n values,\n source: 'ui',\n runAfterChange\n })\n },\n addOption: (option: Partial<Option>) => {\n this.sync.enqueue({\n type: 'addOption',\n option,\n source: 'ui'\n })\n },\n search: this.search.bind(this),\n beforeChange: this.events.beforeChange,\n afterChange: this.events.afterChange\n }\n\n // Setup render class\n this.settings.modalTitle =\n config.settings?.modalTitle ?? getAssociatedLabelText(this.selectEl)\n\n this.render = new Render(\n this.settings,\n this.cssClasses,\n this.store,\n renderCallbacks\n )\n\n // Align JS timeout with --ss-animation-timing (CSS is source of truth)\n this.settings.timeoutDelay = getAnimationTimeout(\n this.render.content.main,\n config.settings?.timeoutDelay\n )\n\n // Single coordinator batches native + API + UI updates (see sync.ts)\n this.sync = new SyncCoordinator({\n select: this.select,\n store: this.store,\n render: this.render,\n events: this.events,\n search: this.search.bind(this)\n })\n\n this.select.onValueChange = (options: Option[]) => {\n this.sync.enqueue({\n type: 'selection',\n values: options.map((option) => option.id),\n source: 'native'\n })\n }\n this.select.onOptionsChange = (data: (Option | Optgroup)[]) => {\n this.sync.enqueue({\n type: 'structure',\n data: data || [],\n source: 'native'\n })\n }\n\n // Open/close state machine — animation wait + outside-click attach timing\n this.lifecycle = new Lifecycle(\n {\n beforeOpen: this.events.beforeOpen,\n afterOpen: this.events.afterOpen,\n beforeClose: (info) => this.events.beforeClose?.(info),\n onClose: (info) => this.applyClose(info),\n afterClose: () => {\n this.render.clearDirectionClasses()\n this.render.finalizeModalClose()\n if (this.events.afterClose) {\n this.events.afterClose()\n }\n },\n onOpenReady: () => this.globalEvents.attachDocumentClick(),\n onCloseReady: () => this.globalEvents.detachDocumentClick()\n },\n {\n timeoutDelay: this.settings.timeoutDelay,\n waitForAnimation: (phase, signal) =>\n this.render.waitForAnimation(phase, signal)\n }\n )\n\n // Resize/scroll/visibility listeners (document click via lifecycle onOpenReady)\n this.globalEvents = new GlobalEvents({\n onDocumentClick: this.documentClick.bind(this),\n onWindowResize: () => {\n if (!this.settings.isOpen && !this.settings.isFullOpen) {\n return\n }\n this.render.moveContent()\n },\n onWindowScroll: () => {\n if (!this.settings.isOpen && !this.settings.isFullOpen) {\n return\n }\n this.render.moveContent()\n },\n onVisibilityChange: () => {\n if (document.hidden) {\n this.close({ source: 'api', selectionChanged: false })\n }\n }\n })\n\n this.render.renderValues()\n this.render.renderOptions(this.store.getData(false))\n\n // Add aria-label or aria-labelledby if exists\n const selectAriaLabel = this.selectEl.getAttribute('aria-label')\n const selectAriaLabelledBy = this.selectEl.getAttribute('aria-labelledby')\n\n if (selectAriaLabel) {\n this.render.main.main.setAttribute('aria-label', selectAriaLabel)\n } else if (selectAriaLabelledBy) {\n this.render.main.main.removeAttribute('aria-label')\n this.render.main.main.setAttribute(\n 'aria-labelledby',\n selectAriaLabelledBy\n )\n } else if (this.selectEl.labels && this.selectEl.labels.length > 0) {\n const labelledByIds = Array.from(this.selectEl.labels).map((label, i) => {\n if (!label.id) {\n label.id = `${this.settings.id}-label-${i}`\n }\n return label.id\n })\n this.render.main.main.removeAttribute('aria-label')\n this.render.main.main.setAttribute(\n 'aria-labelledby',\n labelledByIds.join(' ')\n )\n }\n\n // Add render after original select element\n if (this.selectEl.parentNode) {\n this.selectEl.parentNode.insertBefore(\n this.render.main.main,\n this.selectEl.nextSibling\n )\n }\n\n this.globalEvents.attach({\n listenScroll: this.settings.openPosition === 'auto'\n })\n\n // If disabled lets call it\n if (this.settings.disabled) {\n this.disable()\n }\n\n // If alwaysOpnen then open it\n if (this.settings.alwaysOpen) {\n this.open()\n }\n\n // Set up label handlers to open SlimSelect when label is clicked\n this.select.setupLabelHandlers()\n\n // Add SlimSelect to select element\n ;(this.selectEl as any).slim = this\n }\n\n // Set to enabled and remove disabled classes\n public enable(): void {\n this.settings.disabled = false\n\n this.select.enable()\n this.render.enable()\n }\n\n // Set to disabled and add disabled classes\n public disable(): void {\n this.settings.disabled = true\n\n this.select.disable()\n this.render.disable()\n }\n\n public getData(): Option[] | Optgroup[] {\n return this.store.getData()\n }\n\n public setData(data: (Partial<Option> | Partial<Optgroup>)[]): void {\n // Batched structure sync — rebuilds native select, store, and option list\n this.sync.enqueue({\n type: 'structure',\n data,\n source: 'api'\n })\n }\n\n public getSelected(): string[] {\n let options = this.store.getSelectedOptions()\n if (this.settings.keepOrder) {\n options = this.store.selectedOrderOptions(options)\n }\n return options.map((option) => option.value)\n }\n\n // Will take in a string or array of strings and set the selected by either the id or value\n public setSelected(values: string | string[], runAfterChange = true): void {\n // Lightweight path — store + native + chips only (no full DOM rebuild)\n this.sync.enqueue({\n type: 'selection',\n values,\n source: 'api',\n runAfterChange\n })\n }\n\n public addOption(option: Partial<Option>): void {\n this.sync.enqueue({\n type: 'addOption',\n option,\n source: 'api'\n })\n }\n\n public open(): void {\n // Dont open if disabled\n // Dont do anything if the content is already open\n if (this.settings.disabled || this.settings.isOpen) {\n return\n }\n\n // Cancel in-flight open/close animation wait (rapid toggle)\n this.lifecycle.cancelPending()\n\n // Tell render to open\n this.render.open()\n\n // Focus on input field only if search is enabled\n if (this.settings.showSearch && this.settings.focusSearch) {\n this.render.searchFocus()\n }\n\n this.settings.isOpen = true\n\n // Sync isFullOpen/isOpen after CSS transition (or timeoutDelay fallback)\n void this.lifecycle.requestOpen().then(() => {\n // close() may have run before this async completion (e.g. closeOnSelect)\n if (!this.settings.isOpen) {\n return\n }\n this.settings.isFullOpen = this.lifecycle.isFullOpen\n this.settings.isOpen = this.lifecycle.isOpen\n })\n\n // Reposition when trigger or ancestors resize (absolute content only)\n if (\n this.settings.contentPosition === 'absolute' &&\n !this.render.isModalViewActive()\n ) {\n this.render.startPositionTracking()\n }\n\n const searchValue = this.render.content.search.input.value.trim()\n if (searchValue !== '') {\n this.search(searchValue)\n }\n }\n\n public close(\n info: CloseInfo = { source: 'api', selectionChanged: false }\n ): void {\n // Dont do anything if the content is already closed\n // Dont do anything if alwaysOpen is true\n if (!this.settings.isOpen || this.settings.alwaysOpen) {\n return\n }\n\n void this.lifecycle.requestClose(info).then((closed) => {\n if (!closed) {\n return\n }\n\n // open() may have run before this async completion\n if (this.settings.isOpen) {\n return\n }\n\n this.settings.isOpen = this.lifecycle.isOpen\n this.settings.isFullOpen = this.lifecycle.isFullOpen\n })\n }\n\n /** Sync close — invoked by lifecycle after beforeClose approves. */\n private applyClose(info: CloseInfo): void {\n // Tell render to close\n this.render.close()\n\n // Clear search only if not empty and keepSearch is false\n if (\n !this.settings.keepSearch &&\n this.render.content.search.input.value !== ''\n ) {\n this.sync.flush()\n this.search('') // Clear search\n }\n\n // If we arent tabbing focus back on the main element\n const skipRefocus =\n info.source === 'outside' || info.source === 'toggle'\n this.render.mainFocus(skipRefocus ? 'click' : null)\n\n // Update settings\n this.settings.isOpen = false\n this.settings.isFullOpen = false\n\n this.render.stopPositionTracking()\n }\n\n // Take in string value and search current options\n public search(value: string): void {\n const trimmed = value.trim()\n\n if (trimmed === '') {\n this.render.content.search.input.value = ''\n this.clearSearch()\n return\n }\n\n // Sync programmatic search calls, but never strip spaces from user input\n if (this.render.content.search.input.value !== value) {\n this.render.content.search.input.value = value\n }\n\n if (this.events.search) {\n this.runApiSearch(trimmed)\n return\n }\n\n this.runLocalSearch(trimmed)\n }\n\n private clearSearch(): void {\n this.searchGeneration++\n\n if (!this.events.search && this.render.canFilterOptionsInPlace()) {\n this.render.filterOptionsInPlace('', this.events.searchFilter!)\n this.render.resetSearchFilterState()\n return\n }\n\n this.render.resetSearchFilterState()\n this.sync.enqueue({\n type: 'structure',\n data: this.store.getCatalogData(),\n source: 'api',\n preserveSelection: true\n })\n }\n\n private runLocalSearch(value: string): void {\n if (this.render.canFilterOptionsInPlace()) {\n this.render.filterOptionsInPlace(value, this.events.searchFilter!)\n return\n }\n\n const searchResults = this.store.search(value, this.events.searchFilter!)\n this.render.renderOptions(searchResults)\n }\n\n private runApiSearch(value: string): void {\n const generation = ++this.searchGeneration\n this.render.renderSearching()\n\n const searchResp = this.events.search!(\n value,\n this.store.getSelectedOptions(),\n this.store.getCatalogData()\n )\n\n const applyResults = (\n data: (Partial<Option> | Partial<Optgroup>)[]\n ): void => {\n if (generation !== this.searchGeneration) {\n return\n }\n if (this.render.content.search.input.value.trim() !== value) {\n return\n }\n\n this.sync.enqueue({\n type: 'structure',\n data,\n source: 'api',\n preserveSelection: true,\n isSearchResult: true\n })\n }\n\n if (searchResp instanceof Promise) {\n searchResp.then(applyResults).catch((err: Error | string) => {\n if (generation !== this.searchGeneration) {\n return\n }\n this.render.renderError(typeof err === 'string' ? err : err.message)\n })\n\n return\n }\n\n if (Array.isArray(searchResp)) {\n applyResults(searchResp)\n return\n }\n\n this.render.renderError(\n 'Search event must return a promise or an array of data'\n )\n }\n\n public destroy(): void {\n this.lifecycle.destroy()\n\n this.render.stopPositionTracking()\n\n this.globalEvents.detach({\n listenScroll: this.settings.openPosition === 'auto'\n })\n\n // Delete the store data\n this.store.setData([])\n\n // Remove the render\n this.render.destroy()\n\n // Show the original select element\n this.select.destroy()\n\n delete (this.selectEl as HTMLSelectElement & { slim?: SlimSelect }).slim\n }\n\n // Event listener for document click\n private documentClick(e: Event): void {\n // If the content is not open, there is no need to close it\n if (!this.settings.isOpen) {\n return\n }\n\n // Check if the click was on the content by looking at the parents\n if (\n e.target &&\n !hasClassInTree(e.target as HTMLElement, this.settings.id)\n ) {\n this.close({ source: 'outside', selectionChanged: false })\n }\n }\n}\n","// UMD entry point - only exports the default SlimSelect class\n// This avoids the mixed exports issue for UMD/IIFE builds\nimport SlimSelect, * as namedExports from './index'\n\n// Attach all named exports as properties on the default export\nObject.assign(SlimSelect, namedExports)\n\nexport default SlimSelect\n"],"mappings":"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"}
1
+ {"version":3,"file":"slimselect.iife.js","names":[],"sources":["../src/slim-select/classes.ts","../src/slim-select/animations.ts","../src/slim-select/settings.ts","../src/slim-select/helpers.ts","../src/slim-select/events.ts","../src/slim-select/lifecycle.ts","../src/slim-select/store.ts","../src/slim-select/render.ts","../src/slim-select/mutations.ts","../src/slim-select/select.ts","../src/slim-select/sync.ts","../src/slim-select/index.ts","../src/slim-select/index.umd.ts"],"sourcesContent":["export default class CssClasses {\n public main: string\n // Placeholder\n public placeholder: string\n\n // Values\n public values: string\n public single: string\n public multiString: string\n public max: string\n public value: string\n public valueText: string\n public valueDelete: string\n public valueOut: string\n\n // Deselect\n public deselect: string\n public deselectPath: string // Not a class but whatever\n\n // Arrow\n public arrow: string\n public arrowClose: string // Not a class but whatever\n public arrowOpen: string // Not a class but whatever\n\n // Content\n public content: string\n public contentOpen: string\n public dirAbove: string\n public dirBelow: string\n\n // Search\n public search: string\n public searchHighlighter: string\n public searching: string\n public status: string\n public addable: string\n public addablePath: string // Not a class but whatever\n\n // List optgroups/options\n public list: string\n\n // Optgroup\n public optgroup: string\n public optgroupLabel: string\n public optgroupLabelText: string\n public optgroupActions: string\n public optgroupSelectAll: string // optgroup select all\n public optgroupSelectAllBox: string // Not a class but whatever\n public optgroupSelectAllCheck: string // Not a class but whatever\n public optgroupClosable: string\n\n // Option\n public option: string\n public optionDelete: string // Not a class but whatever\n public highlighted: string\n\n // Modal\n public modalOverlay: string\n public modalDialog: string\n public modalTitle: string\n public modalClose: string\n public modalContent: string\n\n // Misc\n public mainOpen: string\n public close: string\n public selected: string\n public error: string\n public disabled: string\n public hide: string\n\n constructor(classes?: Partial<CssClasses>) {\n if (!classes) {\n classes = {}\n }\n\n let join = (a = '', b = '') => `${a} ${b}`.trim()\n\n this.main = join('ss-main', classes.main)\n this.placeholder = join('ss-placeholder', classes.placeholder)\n this.values = join('ss-values', classes.values)\n this.single = join('ss-single', classes.single)\n this.multiString = join('ss-multi-string', classes.multiString)\n this.max = join('ss-max', classes.max)\n this.value = join('ss-value', classes.value)\n this.valueText = join('ss-value-text', classes.valueText)\n this.valueDelete = join('ss-value-delete', classes.valueDelete)\n this.valueOut = join('ss-value-out', classes.valueOut)\n\n this.deselect = join('ss-deselect', classes.deselect)\n this.deselectPath = classes.deselectPath || 'M10,10 L90,90 M10,90 L90,10'\n this.arrow = join('ss-arrow', classes.arrow)\n this.arrowClose = classes.arrowClose || 'M10,30 L50,70 L90,30'\n this.arrowOpen = classes.arrowOpen || 'M10,70 L50,30 L90,70'\n this.content = join('ss-content', classes.content)\n this.contentOpen = join('ss-open', classes.contentOpen)\n this.dirAbove = join('ss-dir-above', classes.dirAbove)\n this.dirBelow = join('ss-dir-below', classes.dirBelow)\n this.search = join('ss-search', classes.search)\n this.searchHighlighter = join(\n 'ss-search-highlight',\n classes.searchHighlighter\n )\n this.searching = join('ss-searching', classes.searching)\n this.status = join('ss-status', classes.status)\n this.addable = join('ss-addable', classes.addable)\n this.addablePath = classes.addablePath || 'M50,10 L50,90 M10,50 L90,50'\n this.list = join('ss-list', classes.list)\n this.optgroup = join('ss-optgroup', classes.optgroup)\n this.optgroupLabel = join('ss-optgroup-label', classes.optgroupLabel)\n this.optgroupLabelText = join(\n 'ss-optgroup-label-text',\n classes.optgroupLabelText\n )\n this.optgroupActions = join('ss-optgroup-actions', classes.optgroupActions)\n this.optgroupSelectAll = join('ss-selectall', classes.optgroupSelectAll)\n this.optgroupSelectAllBox =\n classes.optgroupSelectAllBox || 'M60,10 L10,10 L10,90 L90,90 L90,50'\n this.optgroupSelectAllCheck =\n classes.optgroupSelectAllCheck || 'M30,45 L50,70 L90,10'\n this.optgroupClosable = join('ss-closable', classes.optgroupClosable)\n this.option = join('ss-option', classes.option)\n this.optionDelete = classes.optionDelete || 'M10,10 L90,90 M10,90 L90,10'\n this.highlighted = join('ss-highlighted', classes.highlighted)\n this.modalOverlay = join('ss-modal-overlay', classes.modalOverlay)\n this.modalDialog = join('ss-modal-dialog', classes.modalDialog)\n this.modalTitle = join('ss-modal-title', classes.modalTitle)\n this.modalClose = join('ss-modal-close', classes.modalClose)\n this.modalContent = join('ss-modal-content', classes.modalContent)\n this.mainOpen = join('ss-open', classes.mainOpen)\n this.close = join('ss-close', classes.close)\n this.selected = join('ss-selected', classes.selected)\n this.error = join('ss-error', classes.error)\n this.disabled = join('ss-disabled', classes.disabled)\n this.hide = join('ss-hide', classes.hide)\n }\n\n public getFirst(name: keyof Omit<CssClasses, 'getFirst'>): string {\n return this[name].split(' ')[0]\n }\n}\n","/**\n * Animation timing helpers.\n *\n * CSS still runs the motion — these keep lifecycle and DOM cleanup aligned with\n * --ss-animation-timing so we are not guessing with hardcoded setTimeout values.\n */\n\n/** Matches default --ss-animation-timing in slimselect.scss */\nconst DEFAULT_DURATION_MS = 200\n\n/** Extra ms added to CSS duration for transitionend/animationend safety-net timeouts. */\nexport const ANIMATION_TIMEOUT_BUFFER_MS = 50\n\n/** .ss-content open/close transitions — wait for both before lifecycle continues. */\nexport const CONTENT_PANEL_TRANSITION_PROPERTIES = [\n 'transform',\n 'opacity'\n] as const\n\n/** Parse a CSS time value (e.g. \"0.2s\", \"200ms\") into milliseconds. */\nexport function parseAnimationDuration(\n cssValue: string,\n fallback = DEFAULT_DURATION_MS\n): number {\n const trimmed = cssValue.trim()\n if (!trimmed) {\n return fallback\n }\n\n if (trimmed.endsWith('ms')) {\n const ms = parseFloat(trimmed)\n return Number.isNaN(ms) ? fallback : ms\n }\n\n if (trimmed.endsWith('s')) {\n const seconds = parseFloat(trimmed)\n return Number.isNaN(seconds) ? fallback : seconds * 1000\n }\n\n const numeric = parseFloat(trimmed)\n return Number.isNaN(numeric) ? fallback : numeric\n}\n\n/** Read --ss-animation-timing from an element's computed styles. */\nexport function getAnimationDuration(\n element: HTMLElement,\n fallback = DEFAULT_DURATION_MS\n): number {\n const computedStyle = getComputedStyle(element)\n const cssValue = computedStyle\n .getPropertyValue('--ss-animation-timing')\n .trim()\n return parseAnimationDuration(cssValue, fallback)\n}\n\n/**\n * Safety-net timeout for animation waits.\n * Derived from --ss-animation-timing (+ buffer). An explicit settings.timeoutDelay\n * is treated as a minimum — never shorter than the CSS-driven duration.\n */\nexport function getAnimationTimeout(\n element: HTMLElement,\n userTimeout?: number,\n fallback = DEFAULT_DURATION_MS\n): number {\n const fromCss =\n getAnimationDuration(element, fallback) + ANIMATION_TIMEOUT_BUFFER_MS\n\n if (userTimeout === undefined) {\n return fromCss\n }\n\n return Math.max(fromCss, userTimeout)\n}\n\n/** Respect user OS accessibility preference and jsdom (no matchMedia). */\nexport function prefersReducedMotion(): boolean {\n if (\n typeof window === 'undefined' ||\n typeof window.matchMedia !== 'function'\n ) {\n return false\n }\n\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches\n}\n\nfunction normalizeTransitionProperties(\n propertyNames?: string | readonly string[]\n): Set<string> | null {\n if (propertyNames === undefined) {\n return null\n }\n\n const list = Array.isArray(propertyNames) ? propertyNames : [propertyNames]\n return new Set(list)\n}\n\n/**\n * Wait for CSS transition(s) to finish, with a timeout fallback.\n *\n * Pass a single property name to resolve on that transitionend, or an array to\n * wait until every listed property has fired (e.g. transform + opacity on .ss-content).\n * Optional AbortSignal cleans up listeners when lifecycle cancels a rapid toggle.\n */\nexport function waitForTransitionEnd(\n element: HTMLElement,\n propertyNames?: string | readonly string[],\n timeoutMs = DEFAULT_DURATION_MS,\n signal?: AbortSignal\n): Promise<void> {\n if (prefersReducedMotion() || signal?.aborted) {\n return Promise.resolve()\n }\n\n const pending = normalizeTransitionProperties(propertyNames)\n\n return new Promise<void>((resolve) => {\n let timer: ReturnType<typeof setTimeout> | null = null\n let settled = false\n\n const finish = () => {\n if (settled) {\n return\n }\n settled = true\n element.removeEventListener('transitionend', onTransitionEnd)\n signal?.removeEventListener('abort', onAbort)\n if (timer) {\n clearTimeout(timer)\n }\n resolve()\n }\n\n const onAbort = () => finish()\n\n const onTransitionEnd = (event: TransitionEvent) => {\n if (event.target !== element) {\n return\n }\n\n if (pending) {\n if (!pending.has(event.propertyName)) {\n return\n }\n pending.delete(event.propertyName)\n if (pending.size > 0) {\n return\n }\n }\n\n finish()\n }\n\n signal?.addEventListener('abort', onAbort, { once: true })\n element.addEventListener('transitionend', onTransitionEnd)\n timer = setTimeout(finish, timeoutMs)\n })\n}\n\n/**\n * Wait for a CSS @keyframes animation to finish, with a timeout fallback.\n *\n * Used when removing multi-select value chips (.ss-value-out). jsdom does not\n * fire animationend, so the timeout wins in unit tests.\n */\nexport function waitForAnimationEnd(\n element: HTMLElement,\n animationName?: string,\n timeoutMs = DEFAULT_DURATION_MS,\n signal?: AbortSignal\n): Promise<void> {\n if (prefersReducedMotion() || signal?.aborted) {\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve) => {\n let timer: ReturnType<typeof setTimeout> | null = null\n let settled = false\n\n const finish = () => {\n if (settled) {\n return\n }\n settled = true\n element.removeEventListener('animationend', onAnimationEnd)\n signal?.removeEventListener('abort', onAbort)\n if (timer) {\n clearTimeout(timer)\n }\n resolve()\n }\n\n const onAbort = () => finish()\n\n const onAnimationEnd = (event: AnimationEvent) => {\n if (event.target !== element) {\n return\n }\n if (animationName && event.animationName !== animationName) {\n return\n }\n finish()\n }\n\n signal?.addEventListener('abort', onAbort, { once: true })\n element.addEventListener('animationend', onAnimationEnd)\n timer = setTimeout(finish, timeoutMs)\n })\n}\n","import { generateID } from './helpers'\n\nexport type ModalSetting = 'off' | 'on' | 'mobile'\n\nexport const MODAL_MOBILE_BREAKPOINT = 768\n\nexport default class Settings {\n public id: string = '' // Primary ID for the select\n public style: string = '' // Style attribute from the select element\n public class: string[] = [] // Class attribute from the select element\n\n // Dynamic settings\n public isMultiple: boolean = false\n public isOpen: boolean = false\n public isFullOpen: boolean = false\n\n // Fields set from constructor\n public disabled: boolean\n public alwaysOpen: boolean\n public showSearch: boolean\n public focusSearch: boolean\n public keepSearch: boolean\n public ariaLabel: string\n public searchPlaceholder: string\n public searchText: string\n public searchingText: string\n public resultsText: string\n public deselectText: string\n public removeText: string\n public searchHighlight: boolean\n public closeOnSelect: boolean\n public contentLocation: HTMLElement | null\n public contentPosition: 'relative' | 'absolute' | 'fixed'\n public contentWidth: string\n public openPosition: 'auto' | 'up' | 'down'\n public placeholderText: string\n public allowDeselect: boolean\n public hideSelected: boolean\n public multiString: boolean\n public keepOrder: boolean\n public showOptionTooltips: boolean\n public minSelected: number\n public maxSelected: number\n public timeoutDelay: number\n public maxValuesShown: number\n public maxValuesMessage: string\n public addableText: string\n public modal: ModalSetting\n public modalTitle: string\n\n constructor(settings?: Partial<Settings>) {\n if (!settings) {\n settings = {}\n }\n\n this.id = 'ss-' + generateID()\n this.style = settings.style || ''\n this.class = settings.class || []\n\n this.disabled = settings.disabled !== undefined ? settings.disabled : false\n this.alwaysOpen =\n settings.alwaysOpen !== undefined ? settings.alwaysOpen : false\n this.showSearch =\n settings.showSearch !== undefined ? settings.showSearch : true\n this.focusSearch =\n settings.focusSearch !== undefined ? settings.focusSearch : true\n this.keepSearch =\n settings.keepSearch !== undefined ? settings.keepSearch : false\n this.ariaLabel = settings.ariaLabel || 'Combobox'\n this.searchPlaceholder = settings.searchPlaceholder || 'Search...'\n this.searchText = settings.searchText || 'No Results'\n this.searchingText = settings.searchingText || 'Searching...'\n this.resultsText = settings.resultsText || '{count} results available'\n this.deselectText = settings.deselectText || 'Clear'\n this.removeText = settings.removeText || 'Remove'\n this.searchHighlight =\n settings.searchHighlight !== undefined ? settings.searchHighlight : false\n this.closeOnSelect =\n settings.closeOnSelect !== undefined ? settings.closeOnSelect : true\n this.contentLocation = settings.contentLocation || document.body\n this.contentPosition = settings.contentPosition || 'absolute'\n this.contentWidth = settings.contentWidth || ''\n this.openPosition = settings.openPosition || 'auto' // options: auto, up, down\n this.placeholderText =\n settings.placeholderText !== undefined\n ? settings.placeholderText\n : 'Select Value'\n this.allowDeselect =\n settings.allowDeselect !== undefined ? settings.allowDeselect : false\n this.hideSelected =\n settings.hideSelected !== undefined ? settings.hideSelected : false\n this.multiString =\n settings.multiString !== undefined ? settings.multiString : false\n this.keepOrder =\n settings.keepOrder !== undefined ? settings.keepOrder : false\n this.showOptionTooltips =\n settings.showOptionTooltips !== undefined\n ? settings.showOptionTooltips\n : false\n this.minSelected = settings.minSelected || 0\n this.maxSelected = settings.maxSelected || 1000\n this.timeoutDelay = settings.timeoutDelay || 200 // Default until SlimSelect reads --ss-animation-timing\n this.maxValuesShown = settings.maxValuesShown || 20\n this.maxValuesMessage = settings.maxValuesMessage || '{number} selected'\n this.addableText = settings.addableText || 'Press \"Enter\" to add {value}'\n this.modal = settings.modal || 'mobile'\n this.modalTitle = settings.modalTitle || ''\n }\n}\n","import type { Optgroup, Option } from './store'\nimport { MODAL_MOBILE_BREAKPOINT, type ModalSetting } from './settings'\n\ntype DataItem = Partial<Option> | Partial<Optgroup>\n\n/** Copy option data attributes into a plain object (not a live DOMStringMap). */\nexport function copyOptionData(\n data?: { [key: string]: string } | DOMStringMap | null\n): { [key: string]: string } {\n if (!data) {\n return {}\n }\n\n const result: { [key: string]: string } = {}\n for (const key of Object.keys(data)) {\n const value = data[key]\n if (value !== undefined) {\n result[key] = value\n }\n }\n return result\n}\n\n/** Label text only — excludes nested form controls (e.g. wrapped select options). */\nexport function getLabelElementText(label: HTMLLabelElement): string {\n const clone = label.cloneNode(true) as HTMLLabelElement\n clone\n .querySelectorAll('select, option, optgroup, textarea, input, button')\n .forEach((el) => el.remove())\n\n return clone.textContent?.replace(/\\s+/g, ' ').trim() || ''\n}\n\n/** Associated label text for a select, or its aria-label when no label is linked. */\nexport function getAssociatedLabelText(select: HTMLSelectElement): string {\n if (select.labels && select.labels.length > 0) {\n const texts = Array.from(select.labels)\n .map(getLabelElementText)\n .filter(Boolean)\n\n if (texts.length > 0) {\n return [...new Set(texts)].join(' ')\n }\n }\n\n return select.getAttribute('aria-label')?.trim() || ''\n}\n\n// Generate an 8 character random string\nexport function generateID(): string {\n return Math.random().toString(36).substring(2, 10)\n}\n\nexport function hasClassInTree(\n element: HTMLElement,\n className: string\n): HTMLElement | null {\n function hasClass(e: HTMLElement, c: string) {\n // If the element has the class return element\n if (c && e && e.classList && e.classList.contains(c)) {\n return e\n }\n\n // If the element has a dataset id of the class return element\n if (c && e && e.dataset && e.dataset.id && e.dataset.id === className) {\n return e\n }\n\n return null\n }\n\n function parentByClass(e: any, c: string): any {\n if (!e || e === (document as any)) {\n return null\n } else if (hasClass(e, c)) {\n return e\n } else {\n return parentByClass(e.parentNode, c)\n }\n }\n\n return hasClass(element, className) || parentByClass(element, className)\n}\n\n// debounce will call the last requested function after the wait time\nexport function debounce<T extends (...args: any[]) => void>(\n func: T,\n wait = 50,\n immediate = false\n): () => void {\n let timeout: any\n return function (this: any, ...args: any[]): void {\n const context = self\n const later = () => {\n timeout = null\n if (!immediate) {\n func.apply(context, args)\n }\n }\n const callNow = immediate && !timeout\n clearTimeout(timeout)\n timeout = setTimeout(later, wait)\n if (callNow) {\n func.apply(context, args)\n }\n }\n}\n\nexport function isEqual(a: any, b: any): boolean {\n return JSON.stringify(a) === JSON.stringify(b)\n}\n\n/** Compare selected id sets regardless of order (multi-select). */\nexport function selectedIdsEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) {\n return false\n }\n\n const sortedA = [...a].sort()\n const sortedB = [...b].sort()\n return sortedA.every((id, i) => id === sortedB[i])\n}\n\nconst OPTION_FIELDS = [\n 'id',\n 'value',\n 'text',\n 'html',\n 'defaultSelected',\n 'selected',\n 'display',\n 'disabled',\n 'placeholder',\n 'class',\n 'style',\n 'mandatory'\n] as const\n\nfunction shallowRecordEqual(\n a: Record<string, string>,\n b: Record<string, string>\n): boolean {\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n\n if (aKeys.length !== bKeys.length) {\n return false\n }\n\n for (const key of aKeys) {\n if (a[key] !== b[key]) {\n return false\n }\n }\n\n return true\n}\n\nfunction normalizedOptionField(\n option: Partial<Option>,\n field: (typeof OPTION_FIELDS)[number]\n): string | boolean | Record<string, string> {\n switch (field) {\n case 'id':\n return option.id || ''\n case 'value':\n return option.value === undefined ? option.text || '' : option.value || ''\n case 'text':\n return option.text || ''\n case 'html':\n return option.html || ''\n case 'defaultSelected':\n return option.defaultSelected ?? false\n case 'selected':\n return option.selected ?? false\n case 'display':\n return option.display ?? true\n case 'disabled':\n return option.disabled ?? false\n case 'placeholder':\n return option.placeholder ?? false\n case 'class':\n return option.class || ''\n case 'style':\n return option.style || ''\n case 'mandatory':\n return option.mandatory ?? false\n default:\n return option.data || {}\n }\n}\n\nfunction isOptgroupItem(item: DataItem): item is Partial<Optgroup> {\n return (\n !!item && typeof item === 'object' && 'label' in item && 'options' in item\n )\n}\n\nfunction optionStructureEqual(a: Partial<Option>, b: Partial<Option>): boolean {\n for (const field of OPTION_FIELDS) {\n const av = normalizedOptionField(a, field)\n const bv = normalizedOptionField(b, field)\n\n if (av !== bv) {\n return false\n }\n }\n\n return shallowRecordEqual(a.data || {}, b.data || {})\n}\n\nfunction optgroupStructureEqual(\n a: Partial<Optgroup>,\n b: Partial<Optgroup>\n): boolean {\n const normalized = (optgroup: Partial<Optgroup>) => ({\n id: optgroup.id || '',\n label: optgroup.label || '',\n selectAll: optgroup.selectAll ?? false,\n closable: optgroup.closable || 'off'\n })\n\n const aNormalized = normalized(a)\n const bNormalized = normalized(b)\n\n if (\n aNormalized.id !== bNormalized.id ||\n aNormalized.label !== bNormalized.label ||\n aNormalized.selectAll !== bNormalized.selectAll ||\n aNormalized.closable !== bNormalized.closable\n ) {\n return false\n }\n\n const aOptions = a.options || []\n const bOptions = b.options || []\n\n if (aOptions.length !== bOptions.length) {\n return false\n }\n\n for (let i = 0; i < aOptions.length; i++) {\n if (!optionStructureEqual(aOptions[i], bOptions[i])) {\n return false\n }\n }\n\n return true\n}\n\n/** Compare option/optgroup arrays without JSON.stringify. */\nexport function dataStructureEqual(a: DataItem[], b: DataItem[]): boolean {\n if (a === b) {\n return true\n }\n\n if (a.length !== b.length) {\n return false\n }\n\n for (let i = 0; i < a.length; i++) {\n const aItem = a[i]\n const bItem = b[i]\n const aIsOptgroup = isOptgroupItem(aItem)\n const bIsOptgroup = isOptgroupItem(bItem)\n\n if (aIsOptgroup !== bIsOptgroup) {\n return false\n }\n\n if (aIsOptgroup) {\n if (!optgroupStructureEqual(aItem, bItem)) {\n return false\n }\n continue\n }\n\n if (\n !optionStructureEqual(aItem as Partial<Option>, bItem as Partial<Option>)\n ) {\n return false\n }\n }\n\n return true\n}\n\nexport function kebabCase(str: string): string {\n const result = str.replace(\n /[A-Z\\u00C0-\\u00D6\\u00D8-\\u00DE]/g,\n (match) => '-' + match.toLowerCase()\n )\n return str[0] === str[0].toUpperCase() ? result.substring(1) : result\n}\n\nexport function shouldUseModalView(\n modal: ModalSetting,\n viewportWidth: number = typeof window !== 'undefined'\n ? window.innerWidth\n : MODAL_MOBILE_BREAKPOINT\n): boolean {\n if (modal === 'on') {\n return true\n }\n if (modal === 'mobile') {\n return viewportWidth < MODAL_MOBILE_BREAKPOINT\n }\n return false\n}\n","/**\n * Global window/document listeners extracted from SlimSelect.\n *\n * Keeps index.ts thinner and makes listener attach/detach testable in isolation.\n * Document click is separate from attach() so it only runs while dropdown is\n * fully open (wired via Lifecycle onOpenReady / onCloseReady).\n */\n\nimport { debounce, hasClassInTree } from './helpers'\n\nexport interface GlobalEventHandlers {\n onDocumentClick: (e: Event) => void\n onWindowResize: () => void\n onWindowScroll: () => void\n onVisibilityChange: () => void\n}\n\nexport default class GlobalEvents {\n private attached = false\n\n constructor(private handlers: GlobalEventHandlers) {}\n\n /** Attach long-lived listeners for the SlimSelect instance lifetime. */\n public attach(options: { listenScroll: boolean }): void {\n if (this.attached) {\n return\n }\n\n this.attached = true\n window.addEventListener('resize', this.resizeHandler, false)\n\n // Scroll listener only needed when openPosition is auto (reposition on scroll)\n if (options.listenScroll) {\n window.addEventListener('scroll', this.scrollHandler, false)\n }\n\n document.addEventListener('visibilitychange', this.visibilityHandler)\n }\n\n /** Attached after open animation completes — closes on outside click. */\n public attachDocumentClick(): void {\n document.addEventListener('click', this.handlers.onDocumentClick)\n }\n\n public detachDocumentClick(): void {\n document.removeEventListener('click', this.handlers.onDocumentClick)\n }\n\n public detach(options: { listenScroll: boolean }): void {\n if (!this.attached) {\n return\n }\n\n this.attached = false\n this.detachDocumentClick()\n window.removeEventListener('resize', this.resizeHandler, false)\n\n if (options.listenScroll) {\n window.removeEventListener('scroll', this.scrollHandler, false)\n }\n\n document.removeEventListener('visibilitychange', this.visibilityHandler)\n }\n\n private resizeHandler = debounce(() => {\n this.handlers.onWindowResize()\n })\n\n private scrollHandler = debounce(() => {\n this.handlers.onWindowScroll()\n })\n\n private visibilityHandler = () => {\n this.handlers.onVisibilityChange()\n }\n}\n\nexport { hasClassInTree }\n","/**\n * Open/close state machine for SlimSelect.\n *\n * Replaces scattered openTimeout/closeTimeout in index.ts with a single flow:\n * closed → opening → open → closing → closed\n *\n * Maps to settings consumers expect:\n * - isOpen: true during opening + open\n * - isFullOpen: true only in open state (after animation / afterOpen)\n *\n * Lifecycle waits for render.waitForAnimation() before firing afterOpen/afterClose.\n * When no animation waiter is provided, falls back to settings.timeoutDelay.\n *\n * Close flow: beforeClose (veto) → onClose (sync DOM/settings) → animation → afterClose\n */\n\nimport type { CloseInfo } from './render'\n\nexport type LifecycleState = 'closed' | 'opening' | 'open' | 'closing'\n\nexport interface LifecycleHandlers {\n beforeOpen?: () => void\n afterOpen?: () => void\n /** Return false to cancel close before any DOM changes. */\n beforeClose?: (info: CloseInfo) => boolean | void\n /** Sync close work — render, focus, settings. Runs after beforeClose approves. */\n onClose?: (info: CloseInfo) => void\n afterClose?: () => void\n /** Fires when fully open — used to attach document click-outside listener. */\n onOpenReady?: () => void\n /** Fires when fully closed — used to detach document click-outside listener. */\n onCloseReady?: () => void\n}\n\nexport interface LifecycleOptions {\n /** Fallback when waitForAnimation is not provided (no CSS element yet). */\n timeoutDelay: number\n waitForAnimation?: (\n phase: 'open' | 'close',\n signal?: AbortSignal\n ) => Promise<void>\n}\n\nexport default class Lifecycle {\n public state: LifecycleState = 'closed'\n private pendingTimer: ReturnType<typeof setTimeout> | null = null\n /** Resolvers for in-flight waitForPhase promises — cancelled on rapid toggle. */\n private waitResolvers: Array<() => void> = []\n /** Incremented on cancelPending(); stale async completions check this before firing handlers. */\n private generation = 0\n private animationAbort: AbortController | null = null\n\n constructor(\n private handlers: LifecycleHandlers,\n private options: LifecycleOptions\n ) {}\n\n public get isOpen(): boolean {\n return this.state === 'opening' || this.state === 'open'\n }\n\n public get isFullOpen(): boolean {\n return this.state === 'open'\n }\n\n public async requestOpen(): Promise<void> {\n if (this.state === 'opening' || this.state === 'open') {\n return\n }\n\n this.cancelPending()\n const gen = ++this.generation\n\n if (this.handlers.beforeOpen) {\n this.handlers.beforeOpen()\n }\n\n this.state = 'opening'\n await this.waitForPhase('open', gen)\n\n // User closed before open animation finished (issue #397)\n if (gen !== this.generation) {\n if (this.state === 'opening') {\n this.state = 'closed'\n }\n return\n }\n\n this.state = 'open'\n\n if (this.handlers.afterOpen) {\n this.handlers.afterOpen()\n }\n\n if (this.handlers.onOpenReady) {\n this.handlers.onOpenReady()\n }\n }\n\n public async requestClose(\n info: CloseInfo = { source: 'api', selectionChanged: false }\n ): Promise<boolean> {\n if (this.state === 'closed' || this.state === 'closing') {\n return false\n }\n\n if (this.handlers.beforeClose && this.handlers.beforeClose(info) === false) {\n return false\n }\n\n this.cancelPending()\n const gen = ++this.generation\n\n if (this.handlers.onClose) {\n this.handlers.onClose(info)\n }\n\n this.state = 'closing'\n await this.waitForPhase('close', gen)\n\n if (gen !== this.generation) {\n return false\n }\n\n this.state = 'closed'\n\n if (this.handlers.afterClose) {\n this.handlers.afterClose()\n }\n\n if (this.handlers.onCloseReady) {\n this.handlers.onCloseReady()\n }\n\n return true\n }\n\n /** Cancel timers and resolve waiting phases — called when open/close race each other. */\n public cancelPending(): void {\n this.generation++\n this.animationAbort?.abort()\n this.animationAbort = null\n if (this.pendingTimer) {\n clearTimeout(this.pendingTimer)\n this.pendingTimer = null\n }\n const resolvers = this.waitResolvers.splice(0)\n for (const resolve of resolvers) {\n resolve()\n }\n }\n\n public destroy(): void {\n this.cancelPending()\n this.state = 'closed'\n }\n\n /**\n * Wait for the CSS animation to finish (or timeoutDelay when no waiter exists).\n * cancelPending() resolves the wait early for rapid open/close toggles.\n */\n private waitForPhase(\n phase: 'open' | 'close',\n gen: number\n ): Promise<void> {\n return new Promise<void>((resolve) => {\n let settled = false\n const finish = () => {\n if (settled) {\n return\n }\n settled = true\n const idx = this.waitResolvers.indexOf(finish)\n if (idx !== -1) {\n this.waitResolvers.splice(idx, 1)\n }\n resolve()\n }\n\n this.waitResolvers.push(finish)\n\n if (this.options.waitForAnimation) {\n const controller = new AbortController()\n this.animationAbort = controller\n void this.options\n .waitForAnimation(phase, controller.signal)\n .catch(() => undefined)\n .finally(() => {\n if (this.animationAbort === controller) {\n this.animationAbort = null\n }\n finish()\n })\n } else {\n this.pendingTimer = setTimeout(() => {\n this.pendingTimer = null\n finish()\n }, this.options.timeoutDelay)\n }\n }).then(() => {\n if (gen !== this.generation) {\n return\n }\n })\n }\n}\n","import { copyOptionData, generateID } from './helpers'\n\nexport class Option {\n id: string\n value: string\n text: string\n html: string\n defaultSelected: boolean\n selected: boolean\n display: boolean\n disabled: boolean\n placeholder: boolean\n class: string\n style: string\n data: { [key: string]: string }\n mandatory: boolean\n\n constructor(option: Partial<Option>) {\n this.id = !option.id || option.id === '' ? generateID() : option.id\n this.value =\n option.value === undefined ? option.text || '' : option.value || ''\n this.text = option.text || ''\n this.html = option.html || ''\n this.defaultSelected =\n option.defaultSelected !== undefined ? option.defaultSelected : false\n this.selected = option.selected !== undefined ? option.selected : false\n this.display = option.display !== undefined ? option.display : true\n this.disabled = option.disabled !== undefined ? option.disabled : false\n this.mandatory = option.mandatory !== undefined ? option.mandatory : false\n this.placeholder =\n option.placeholder !== undefined ? option.placeholder : false\n this.class = option.class || ''\n this.style = option.style || ''\n this.data = copyOptionData(option.data)\n }\n}\nexport class Optgroup {\n public id: string\n public label: string\n public selectAll: boolean\n public closable: 'off' | 'open' | 'close'\n public options: Partial<Option>[]\n\n constructor(optgroup: Partial<Optgroup>) {\n this.id = !optgroup.id || optgroup.id === '' ? generateID() : optgroup.id\n this.label = optgroup.label || ''\n this.selectAll =\n optgroup.selectAll === undefined ? false : optgroup.selectAll\n this.closable = optgroup.closable || 'off'\n\n // If options exist, loop through options and create new option class\n // and set the options to the optgroup options field\n this.options = []\n if (optgroup.options) {\n for (const o of optgroup.options) {\n this.options.push(new Option(o))\n }\n }\n }\n}\n\nexport default class Store {\n private selectType: 'single' | 'multiple' = 'single'\n\n // Main data set, never null\n private data: (Option | Optgroup)[] = []\n private selectedOrder: string[] = []\n /** Baseline option list — restored when search is cleared (API results are temporary). */\n private catalog: (Option | Optgroup)[] | null = null\n\n constructor(\n type: 'single' | 'multiple',\n data: (Partial<Option> | Partial<Optgroup>)[]\n ) {\n this.selectType = type\n this.setData(data)\n this.snapshotCatalog()\n }\n\n // Validate DataArrayPartial\n public validateDataArray(\n data: (Partial<Option> | Partial<Optgroup>)[]\n ): Error | null {\n if (!Array.isArray(data)) {\n return new Error('Data must be an array')\n }\n\n // Loop through each data object\n for (let dataObj of data) {\n if (!dataObj) continue\n\n // Optgroup\n if (dataObj instanceof Optgroup || 'label' in dataObj) {\n if (!('label' in dataObj)) {\n return new Error('Optgroup must have a label')\n }\n\n if ('options' in dataObj && dataObj.options) {\n for (let option of dataObj.options) {\n const validationError = this.validateOption(option)\n if (validationError) {\n return validationError\n }\n }\n }\n } else if (dataObj instanceof Option || 'text' in dataObj) {\n const validationError = this.validateOption(dataObj)\n if (validationError) {\n return validationError\n }\n } else {\n return new Error('Data object must be a valid optgroup or option')\n }\n }\n\n return null\n }\n\n // Validate Option\n public validateOption(option: Partial<Option>): Error | null {\n if (!('text' in option)) {\n return new Error('Option must have a text')\n }\n\n return null\n }\n\n public partialToFullData(\n data: (Partial<Option> | Partial<Optgroup>)[]\n ): (Option | Optgroup)[] {\n let dataFinal: (Option | Optgroup)[] = []\n data.forEach((dataObj) => {\n if (!dataObj) return\n\n // Optgroup\n if (dataObj instanceof Optgroup || 'label' in dataObj) {\n let optOptions: Option[] = []\n if ('options' in dataObj && dataObj.options) {\n dataObj.options.forEach((option: Partial<Option>) => {\n optOptions.push(new Option(option))\n })\n }\n\n if (optOptions.length > 0) {\n dataFinal.push(new Optgroup(dataObj as Partial<Optgroup>))\n }\n }\n\n // Option\n if (dataObj instanceof Option || 'text' in dataObj) {\n dataFinal.push(new Option(dataObj as Partial<Option>))\n }\n })\n\n return dataFinal\n }\n\n /** Snapshot the current data as the catalog baseline (not called for API search results). */\n public snapshotCatalog(): void {\n this.catalog = this.cloneData(this.data)\n }\n\n /** Catalog baseline used when clearing search. */\n public getCatalogData(): (Option | Optgroup)[] {\n return this.cloneData(this.catalog ?? this.data)\n }\n\n private cloneData(data: (Option | Optgroup)[]): (Option | Optgroup)[] {\n return data.map((item) => {\n if (item instanceof Optgroup) {\n return new Optgroup({\n id: item.id,\n label: item.label,\n selectAll: item.selectAll,\n closable: item.closable,\n options: item.options.map((option) =>\n new Option(option instanceof Option ? { ...option } : option)\n )\n })\n }\n\n return new Option({ ...(item as Option) })\n })\n }\n\n private optionMatchesSelected(\n candidate: Option,\n selected: Option\n ): boolean {\n if (candidate.id === selected.id) {\n return true\n }\n\n return (\n selected.value !== '' &&\n candidate.value !== '' &&\n candidate.value === selected.value\n )\n }\n\n private findOptionInData(\n data: (Option | Optgroup)[],\n selected: Option\n ): Option | null {\n for (const item of data) {\n if (item instanceof Option) {\n if (this.optionMatchesSelected(item, selected)) {\n return item\n }\n continue\n }\n\n for (const option of item.options as Option[]) {\n if (this.optionMatchesSelected(option, selected)) {\n return option\n }\n }\n }\n\n return null\n }\n\n public setData(\n data: (Partial<Option> | Partial<Optgroup>)[],\n preserveSelected: boolean = false\n ) {\n // Convert new data to full data array\n const newData = this.partialToFullData(data)\n\n let selectedOptionsBeforeUpdate: Option[] = []\n\n if (preserveSelected) {\n // Get currently selected options before updating data\n selectedOptionsBeforeUpdate = this.getSelectedOptions()\n\n // Check which selected options are missing from new data\n const missingSelected: Option[] = []\n selectedOptionsBeforeUpdate.forEach((selectedOption) => {\n if (!this.findOptionInData(newData, selectedOption)) {\n missingSelected.push(selectedOption)\n }\n })\n\n // Add missing selected options to the beginning of the data\n this.data = [...missingSelected, ...newData]\n\n const allowEmptySelection =\n this.selectType === 'single' &&\n selectedOptionsBeforeUpdate.length === 0\n const selectedIds = selectedOptionsBeforeUpdate.map((selected) => {\n const match = this.findOptionInData(this.data, selected)\n return match ? match.id : selected.id\n })\n\n this.setSelectedBy('id', selectedIds, allowEmptySelection)\n } else {\n this.data = newData\n }\n\n // Run this.data through setSelected by value\n // to set the selected property and clean any wrong selected\n if (!preserveSelected && this.selectType === 'single') {\n this.setSelectedBy('id', this.getSelected(), false)\n }\n }\n\n // Get data will return all the data (cloned by default for public API safety)\n public getData(clone = true): Option[] | Optgroup[] {\n return this.filter(null, true, clone) as Option[] | Optgroup[]\n }\n\n // Get data options will return the data as a flat array of just options\n public getDataOptions(clone = true): Option[] {\n return this.filter(null, false, clone) as Option[]\n }\n\n public addOption(option: Partial<Option>, addToStart: boolean = false) {\n if (addToStart) {\n let data = [new Option(option)] as (Option | Optgroup)[]\n this.setData(data.concat(this.getData()))\n } else {\n this.setData(this.getData().concat(new Option(option)))\n }\n }\n\n // Pass in an array of id that will loop through\n // each option and set the selected property to true\n // but also clean selected by determining selectType\n // When allowEmptySelection is true (e.g. after search with no prior selection), single select will not auto-select the first option\n public setSelectedBy(\n selectedType: 'id' | 'value',\n selectedValues: string[],\n allowEmptySelection: boolean = false\n ) {\n let firstOption: Partial<Option> | null = null\n let hasSelected = false\n const selectedObjects: Partial<Option>[] = []\n\n for (let dataObj of this.data) {\n // Optgroup\n if (dataObj instanceof Optgroup) {\n for (let option of dataObj.options as Partial<Option>[]) {\n if (!firstOption) {\n firstOption = option\n }\n\n let optionValue = option[selectedType] || ''\n option.selected = hasSelected\n ? false\n : selectedValues.includes(optionValue)\n\n // If the option is selected, set hasSelected to true\n // for single based selects\n if (option.selected) {\n selectedObjects.push(option)\n\n if (this.selectType === 'single') {\n hasSelected = true\n }\n }\n }\n }\n\n // Option\n if (dataObj instanceof Option) {\n if (!firstOption) {\n firstOption = dataObj\n }\n\n dataObj.selected = hasSelected\n ? false\n : selectedValues.includes(dataObj[selectedType])\n\n // If the option is selected, set hasSelected to true\n // for single based selects\n if (dataObj.selected) {\n selectedObjects.push(dataObj)\n\n if (this.selectType === 'single') {\n hasSelected = true\n }\n }\n }\n }\n\n // If no options are selected, select the first option (unless allowEmptySelection, e.g. after search with no selection)\n if (\n this.selectType === 'single' &&\n firstOption &&\n !hasSelected &&\n !allowEmptySelection\n ) {\n firstOption.selected = true\n selectedObjects.push(firstOption)\n }\n\n // Put together a list of selected ids in the order of the selected values\n const selectedIds = selectedValues.map((value) => {\n return (\n selectedObjects.find((option) => option[selectedType] === value)?.id ||\n ''\n )\n })\n\n this.selectedOrder = selectedIds\n }\n\n public getSelected(): string[] {\n return this.getSelectedOptions().map((option) => option.id)\n }\n\n public getSelectedValues(): string[] {\n return this.getSelectedOptions().map((option) => option.value)\n }\n\n public getSelectedOptions(): Option[] {\n const selected: Option[] = []\n\n for (const dataObj of this.data) {\n if (dataObj instanceof Optgroup) {\n for (const option of dataObj.options as Option[]) {\n if (option.selected) {\n selected.push(option)\n }\n }\n } else if (dataObj.selected) {\n selected.push(dataObj)\n }\n }\n\n return selected\n }\n\n public getOptgroupByID(id: string): Optgroup | null {\n // Loop through each data object\n // and if optgroup is found, return it\n for (let dataObj of this.data) {\n if (dataObj instanceof Optgroup && dataObj.id === id) {\n return dataObj\n }\n }\n\n return null\n }\n\n public getOptionByID(id: string): Option | null {\n for (const dataObj of this.data) {\n if (dataObj instanceof Optgroup) {\n for (const option of dataObj.options as Option[]) {\n if (option.id === id) {\n return option\n }\n }\n } else if (dataObj.id === id) {\n return dataObj\n }\n }\n\n return null\n }\n\n public getSelectType(): string {\n return this.selectType\n }\n\n public getFirstOption(): Option | null {\n let option: Option | null = null\n for (let dataObj of this.data) {\n if (dataObj instanceof Optgroup) {\n option = dataObj.options[0] as Option\n } else if (dataObj instanceof Option) {\n option = dataObj\n }\n\n if (option) {\n break\n }\n }\n return option\n }\n\n // Take in search string and return filtered list of values\n public search(\n search: string,\n searchFilter: (opt: Option, search: string) => boolean\n ): (Option | Optgroup)[] {\n search = search.trim()\n\n // If search is empty, return all data\n if (search === '') {\n return this.getData(false)\n }\n\n // Run filter with search function (read-only view for render)\n return this.filter((opt: Option): boolean => {\n return searchFilter(opt, search)\n }, true, false)\n }\n\n private createOptgroupView(\n source: Optgroup,\n options: Option[]\n ): Optgroup {\n const view = new Optgroup({\n id: source.id,\n label: source.label,\n selectAll: source.selectAll,\n closable: source.closable,\n options: []\n })\n view.options = options\n return view\n }\n\n // Filter takes in a function that will be used to filter the data\n // This will also keep optgroups of sub options meet the filter requirements\n public filter(\n filter: { (opt: Option): boolean } | null,\n includeOptgroup: boolean,\n clone = true\n ): (Option | Optgroup)[] {\n const dataSearch: (Option | Optgroup)[] = []\n this.data.forEach((dataObj: Option | Optgroup) => {\n // Optgroup\n if (dataObj instanceof Optgroup) {\n let optOptions: Option[] = []\n let options = dataObj.options as Option[]\n options.forEach((option: Option) => {\n if (!filter || filter(option as Option)) {\n // If you dont want to include optgroups\n // just push to the dataSearch array\n if (!includeOptgroup) {\n dataSearch.push(clone ? new Option(option) : option)\n } else {\n optOptions.push(clone ? new Option(option) : option)\n }\n }\n })\n\n // If we pushed any options to the optOptions array\n // push the optgroup to the dataSearch array\n if (optOptions.length > 0) {\n if (clone) {\n let optgroup = new Optgroup(dataObj)\n optgroup.options = optOptions\n dataSearch.push(optgroup)\n } else {\n dataSearch.push(this.createOptgroupView(dataObj, optOptions))\n }\n }\n }\n\n // Option\n if (dataObj instanceof Option) {\n if (!filter || filter(dataObj)) {\n dataSearch.push(clone ? new Option(dataObj) : dataObj)\n }\n }\n })\n\n return dataSearch\n }\n\n // Take in an array of options and reoder them based upon the selected order\n public selectedOrderOptions(options: Option[]): Option[] {\n const newOrder: Option[] = []\n this.selectedOrder.forEach((id) => {\n const option = options.find((opt) => opt.id === id)\n if (option) {\n newOrder.push(option)\n }\n })\n\n // add any remaining options that were not in the selected order\n options.forEach((option) => {\n let isIn = false\n newOrder.forEach((selectedOption) => {\n if (option.id === selectedOption.id) {\n isIn = true\n\n return\n }\n })\n\n if (!isIn) {\n newOrder.push(option)\n }\n })\n\n return newOrder\n }\n}\n","import { debounce, shouldUseModalView } from './helpers'\nimport {\n CONTENT_PANEL_TRANSITION_PROPERTIES,\n getAnimationDuration,\n getAnimationTimeout,\n waitForAnimationEnd,\n waitForTransitionEnd\n} from './animations'\nimport Settings from './settings'\nimport Store, { Optgroup, Option } from './store'\nimport CssClasses from './classes'\n\nexport type CloseSource =\n | 'select'\n | 'deselect'\n | 'outside'\n | 'toggle'\n | 'escape'\n | 'tab'\n | 'modal'\n | 'api'\n\nexport interface CloseInfo {\n source: CloseSource\n option?: Option\n selectionChanged: boolean\n}\n\nexport interface Callbacks {\n open: () => void\n close: (info?: CloseInfo) => void\n addable?: (\n value: string\n ) =>\n | Promise<Partial<Option> | string>\n | Partial<Option>\n | string\n | false\n | undefined\n | null\n | Error\n setSelected: (value: string | string[], runAfterChange: boolean) => void\n addOption: (option: Option) => void\n search: (search: string) => void\n beforeChange?: (newVal: Option[], oldVal: Option[]) => boolean | void\n afterChange?: (newVal: Option[]) => void\n}\n\nexport interface Main {\n main: HTMLDivElement\n values: HTMLDivElement\n deselect: {\n main: HTMLDivElement\n svg: SVGSVGElement\n path: SVGPathElement\n }\n arrow: {\n main: SVGSVGElement\n path: SVGPathElement\n }\n}\n\nexport interface Content {\n main: HTMLDivElement\n search: Search\n status: HTMLDivElement\n list: HTMLDivElement\n}\n\nexport interface Search {\n main: HTMLDivElement\n input: HTMLInputElement\n addable?: {\n main: HTMLDivElement\n svg: SVGSVGElement\n path: SVGPathElement\n }\n}\n\nexport interface ModalElements {\n overlay: HTMLDivElement\n dialog: HTMLDivElement\n closeButton: HTMLButtonElement\n title: HTMLDivElement | null\n}\n\nexport default class Render {\n public settings: Settings\n public store: Store\n public callbacks: Callbacks\n\n // Used to compute the range selection\n private lastSelectedOption: Option | null\n private lastRenderedOptions: Option[]\n private optionsListIsFullData = false\n private lastSearchFilterTerm = ''\n\n // Timeout tracking for cleanup\n\n // Elements\n public main: Main\n public content: Content\n\n // Classes\n public classes: CssClasses\n\n private positionObserver: ResizeObserver | null = null\n private positionObserverRaf = 0\n private overflowShiftRaf = 0\n\n private modalElements: ModalElements | null = null\n private modalSessionActive: boolean | null = null\n private bodyScrollLocked = false\n private savedBodyOverflow = ''\n\n constructor(\n settings: Required<Settings>,\n classes: Required<CssClasses>,\n store: Store,\n callbacks: Callbacks\n ) {\n this.store = store\n this.settings = settings\n this.classes = classes\n this.callbacks = callbacks\n this.lastSelectedOption = null\n this.lastRenderedOptions = []\n\n this.main = this.mainDiv()\n this.content = this.contentDiv()\n\n // Add classes and styles to main/content\n this.updateClassStyles()\n this.updateAriaAttributes()\n\n // Position content off-screen initially to prevent scrollbars\n // This must be after updateClassStyles() since it removes all style attributes\n // The main element isn't in the DOM yet, so getBoundingClientRect() would return zeros\n // Once opened, moveContent() will position it correctly\n if (this.settings.contentPosition !== 'relative') {\n this.content.main.style.top = '-9999px'\n this.content.main.style.left = '-9999px'\n this.content.main.style.margin = '0'\n this.content.main.style.width = 'auto'\n }\n\n // Add content to the content location settings\n if (this.settings.contentLocation) {\n this.settings.contentLocation.appendChild(this.content.main)\n }\n\n if (this.settings.modal !== 'off' && !this.settings.alwaysOpen) {\n this.modalElements = this.createModalElements()\n document.body.appendChild(this.modalElements.overlay)\n }\n }\n\n // Helper method to add classes that may contain spaces\n // Splits by spaces and adds each class individually to avoid DOMException\n private requestClose(\n source: CloseSource,\n options?: { option?: Option; selectionChanged?: boolean }\n ): void {\n this.callbacks.close({\n source,\n option: options?.option,\n selectionChanged: options?.selectionChanged ?? false\n })\n }\n\n private selectionChanged(before: Option[], after: Option[]): boolean {\n if (before.length !== after.length) {\n return true\n }\n\n const beforeIds = before.map((o) => o.id).sort()\n const afterIds = after.map((o) => o.id).sort()\n\n return beforeIds.some((id, index) => id !== afterIds[index])\n }\n\n private closeOnSingleSelectReclick(storeOption: Option): void {\n if (this.settings.closeOnSelect) {\n this.requestClose('select', {\n option: storeOption,\n selectionChanged: false\n })\n }\n }\n\n public addClasses(\n element: HTMLElement | SVGElement,\n classValue: string\n ): void {\n if (!classValue || classValue.trim() === '') {\n return\n }\n const classes = classValue.split(' ').filter((c) => c.trim() !== '')\n for (const cls of classes) {\n element.classList.add(cls.trim())\n }\n }\n\n // Helper method to remove classes that may contain spaces\n public removeClasses(\n element: HTMLElement | SVGElement,\n classValue: string\n ): void {\n if (!classValue || classValue.trim() === '') {\n return\n }\n const classes = classValue.split(' ').filter((c) => c.trim() !== '')\n for (const cls of classes) {\n element.classList.remove(cls.trim())\n }\n }\n\n // Remove disabled classes\n public enable(): void {\n // Remove disabled class\n this.removeClasses(this.main.main, this.classes.disabled)\n this.main.main.setAttribute('aria-disabled', 'false')\n\n // Set search input to \"enabled\"\n this.content.search.input.disabled = false\n }\n\n // Set disabled classes\n public disable(): void {\n // Add disabled class\n this.addClasses(this.main.main, this.classes.disabled)\n this.main.main.setAttribute('aria-disabled', 'true')\n\n // Set search input to disabled\n this.content.search.input.disabled = true\n }\n\n public open(): void {\n this.main.arrow.path.setAttribute('d', this.classes.arrowOpen)\n this.main.main.setAttribute('aria-expanded', 'true')\n\n const useModal = this.resolveModalView()\n\n if (!useModal) {\n const isAbove = this.settings.openPosition === 'up'\n const dirClass = isAbove ? this.classes.dirAbove : this.classes.dirBelow\n this.addClasses(this.main.main, dirClass)\n this.addClasses(this.content.main, dirClass)\n }\n\n // Add open class to content to trigger open animation\n this.addClasses(this.content.main, this.classes.contentOpen)\n\n // Make search visible to screen readers when opened\n this.content.search.input.removeAttribute('aria-hidden')\n\n if (useModal) {\n this.showModal()\n } else {\n this.moveContent()\n }\n\n // Move to last selected option\n const selectedOptions = this.store.getSelectedOptions()\n if (selectedOptions.length) {\n const selectedId = selectedOptions[selectedOptions.length - 1].id\n const selectedOption = this.content.list.querySelector(\n '[data-id=\"' + selectedId + '\"]'\n ) as HTMLElement\n if (selectedOption) {\n this.ensureElementInView(this.content.list, selectedOption)\n }\n }\n }\n\n public isModalViewActive(): boolean {\n return this.modalSessionActive === true\n }\n\n private resolveModalView(): boolean {\n if (\n this.settings.alwaysOpen ||\n this.settings.modal === 'off' ||\n !this.modalElements\n ) {\n return false\n }\n\n if (this.modalSessionActive === null) {\n this.modalSessionActive = shouldUseModalView(this.settings.modal)\n }\n\n return this.modalSessionActive\n }\n\n private createModalElements(): ModalElements {\n const overlay = document.createElement('div')\n this.addClasses(overlay, this.classes.modalOverlay)\n this.addClasses(overlay, this.classes.hide)\n overlay.dataset.id = this.settings.id\n\n const dialog = document.createElement('div')\n this.addClasses(dialog, this.classes.modalDialog)\n dialog.setAttribute('role', 'dialog')\n dialog.setAttribute('aria-modal', 'true')\n\n let title: HTMLDivElement | null = null\n if (this.settings.modalTitle) {\n title = document.createElement('div')\n this.addClasses(title, this.classes.modalTitle)\n title.id = `${this.settings.id}-modal-title`\n title.textContent = this.settings.modalTitle\n dialog.setAttribute('aria-labelledby', title.id)\n } else {\n dialog.setAttribute('aria-label', this.settings.ariaLabel)\n }\n\n const closeButton = document.createElement('button')\n closeButton.type = 'button'\n this.addClasses(closeButton, this.classes.modalClose)\n closeButton.setAttribute('aria-label', 'Close')\n closeButton.onclick = (e: Event) => {\n e.stopPropagation()\n this.requestClose('modal')\n }\n\n const closeSvg = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'svg'\n )\n closeSvg.setAttribute('viewBox', '0 0 100 100')\n const closePath = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n closePath.setAttribute('d', this.classes.deselectPath)\n closeSvg.appendChild(closePath)\n closeButton.appendChild(closeSvg)\n\n overlay.onclick = (e: Event) => {\n if (e.target === overlay) {\n this.requestClose('modal')\n }\n }\n\n if (title) {\n dialog.appendChild(title)\n }\n overlay.appendChild(dialog)\n\n return { overlay, dialog, closeButton, title }\n }\n\n private showModal(): void {\n if (!this.modalElements) {\n return\n }\n\n this.modalElements.dialog.appendChild(this.content.main)\n this.addClasses(this.content.main, this.classes.modalContent)\n this.content.main.appendChild(this.modalElements.closeButton)\n this.content.main.style.top = ''\n this.content.main.style.left = ''\n this.content.main.style.margin = ''\n this.content.main.style.width = ''\n\n this.removeClasses(this.modalElements.overlay, this.classes.hide)\n requestAnimationFrame(() => {\n if (!this.modalElements) {\n return\n }\n this.addClasses(this.modalElements.overlay, this.classes.contentOpen)\n })\n\n this.lockBodyScroll()\n }\n\n private lockBodyScroll(): void {\n if (this.bodyScrollLocked) {\n return\n }\n\n this.savedBodyOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n this.bodyScrollLocked = true\n }\n\n private unlockBodyScroll(): void {\n if (!this.bodyScrollLocked) {\n return\n }\n\n document.body.style.overflow = this.savedBodyOverflow\n this.bodyScrollLocked = false\n this.savedBodyOverflow = ''\n }\n\n private restoreContentOffscreen(): void {\n if (this.settings.contentLocation) {\n this.settings.contentLocation.appendChild(this.content.main)\n }\n\n if (this.settings.contentPosition !== 'relative') {\n this.content.main.style.top = '-9999px'\n this.content.main.style.left = '-9999px'\n this.content.main.style.margin = '0'\n this.content.main.style.width = 'auto'\n }\n }\n\n /** Tear down modal shell after close animation completes. */\n public finalizeModalClose(): void {\n if (!this.modalElements) {\n return\n }\n\n if (this.content.main.parentElement !== this.modalElements.dialog) {\n return\n }\n\n this.addClasses(this.modalElements.overlay, this.classes.hide)\n this.removeClasses(this.modalElements.overlay, this.classes.contentOpen)\n this.removeClasses(this.content.main, this.classes.modalContent)\n this.modalElements.closeButton.remove()\n this.restoreContentOffscreen()\n this.unlockBodyScroll()\n }\n\n /** Used by Lifecycle — wait for .ss-content CSS transition before afterOpen/afterClose. */\n public waitForAnimation(\n phase: 'open' | 'close',\n signal?: AbortSignal\n ): Promise<void> {\n const timeout = getAnimationTimeout(\n this.content.main,\n this.settings.timeoutDelay\n )\n return waitForTransitionEnd(\n this.content.main,\n CONTENT_PANEL_TRANSITION_PROPERTIES,\n timeout,\n signal\n )\n }\n\n public close(): void {\n this.main.main.setAttribute('aria-expanded', 'false')\n this.main.arrow.path.setAttribute('d', this.classes.arrowClose)\n\n const wasModal = this.modalSessionActive === true\n\n // Remove open class from content to trigger close animation\n // Direction on content persists for transform-origin during the panel animation\n this.removeClasses(this.content.main, this.classes.contentOpen)\n\n if (!wasModal) {\n this.removeClasses(this.main.main, this.classes.dirAbove)\n this.removeClasses(this.main.main, this.classes.dirBelow)\n }\n\n if (wasModal && this.modalElements) {\n this.removeClasses(this.modalElements.overlay, this.classes.contentOpen)\n }\n\n this.modalSessionActive = null\n\n // Hide search from screen readers when closed\n this.content.search.input.setAttribute('aria-hidden', 'true')\n\n // Clear active descendant when closed\n this.main.main.removeAttribute('aria-activedescendant')\n }\n\n /** Remove open-direction classes after close animation (lifecycle afterClose). */\n public clearDirectionClasses(): void {\n this.removeClasses(this.main.main, this.classes.dirAbove)\n this.removeClasses(this.main.main, this.classes.dirBelow)\n this.removeClasses(this.content.main, this.classes.dirAbove)\n this.removeClasses(this.content.main, this.classes.dirBelow)\n }\n\n public updateClassStyles(): void {\n // Clear all classes and styles\n this.main.main.className = ''\n this.main.main.removeAttribute('style')\n this.content.main.className = ''\n this.content.main.removeAttribute('style')\n\n // Make sure main/content has its base class\n this.addClasses(this.main.main, this.classes.main)\n this.addClasses(this.content.main, this.classes.content)\n\n // Add styles\n if (this.settings.style !== '') {\n this.main.main.style.cssText = this.settings.style\n this.content.main.style.cssText = this.settings.style\n }\n\n // Add classes from the native select to both main and content\n if (this.settings.class.length) {\n for (const c of this.settings.class) {\n if (c.trim() !== '') {\n this.main.main.classList.add(c.trim())\n this.content.main.classList.add(c.trim())\n }\n }\n }\n\n // Misc classes\n // Add content position class\n if (\n this.settings.contentPosition === 'relative' ||\n this.settings.contentPosition === 'fixed'\n ) {\n this.content.main.classList.add('ss-' + this.settings.contentPosition)\n }\n }\n\n public updateAriaAttributes() {\n const listboxId = this.content.list.id\n\n // Main combobox\n this.main.main.role = 'combobox'\n this.main.main.setAttribute('aria-haspopup', 'listbox')\n this.main.main.setAttribute('aria-controls', listboxId)\n this.main.main.setAttribute('aria-expanded', 'false')\n\n this.content.list.setAttribute('role', 'listbox')\n this.content.list.setAttribute(\n 'aria-label',\n this.settings.ariaLabel + ' listbox'\n )\n\n // Add aria-multiselectable for multiple selects\n if (this.settings.isMultiple) {\n this.content.list.setAttribute('aria-multiselectable', 'true')\n }\n\n // Search input should also control the listbox\n this.content.search.input.setAttribute('aria-controls', listboxId)\n }\n\n public mainDiv(): Main {\n // Create main container\n const main = document.createElement('div')\n\n // Add id to data-id\n main.dataset.id = this.settings.id\n // main.id = this.settings.id+'-main' // Remove for now as it is not needed and add duplicate id errors\n\n // Add label\n main.setAttribute('aria-label', this.settings.ariaLabel)\n\n // Set tabable to allow tabbing to the element\n main.tabIndex = 0\n\n // Deal with keyboard events on the main div\n // This is to allow for normal selecting\n // when you may not have a search bar\n main.onkeydown = (e: KeyboardEvent): boolean => {\n // Convert above if else statemets to switch\n switch (e.key) {\n case 'ArrowUp':\n case 'ArrowDown':\n this.callbacks.open()\n e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up')\n return false\n case 'Tab':\n this.requestClose('tab')\n return true // Continue doing normal tabbing\n case 'Enter':\n case ' ':\n this.callbacks.open()\n const highlighted = this.content.list.querySelector(\n '.' + this.classes.getFirst('highlighted')\n ) as HTMLDivElement\n if (highlighted) {\n highlighted.click()\n }\n return false\n case 'Escape':\n this.requestClose('escape')\n return false\n }\n\n // Check if they type a-z, A-Z and 0-9\n if (e.key.length === 1) {\n this.callbacks.open()\n }\n\n return true\n }\n\n // Add onclick for main div\n main.onclick = (e: Event): void => {\n // Dont do anything if disabled\n if (this.settings.disabled) {\n return\n }\n\n this.settings.isOpen\n ? this.requestClose('toggle')\n : this.callbacks.open()\n }\n\n // Add values\n const values = document.createElement('div')\n this.addClasses(values, this.classes.values)\n main.appendChild(values)\n\n // Add deselect\n const deselect = document.createElement('div')\n this.addClasses(deselect, this.classes.deselect)\n deselect.setAttribute('role', 'button')\n deselect.setAttribute('aria-label', this.settings.deselectText)\n deselect.setAttribute('tabindex', '0')\n\n // Check if deselect is to be shown or not\n const selectedOptions = this.store?.getSelectedOptions()\n if (\n !this.settings.allowDeselect ||\n (this.settings.isMultiple &&\n selectedOptions &&\n selectedOptions.length <= 0) ||\n this.isAtMinSelected()\n ) {\n this.addClasses(deselect, this.classes.hide)\n } else {\n this.removeClasses(deselect, this.classes.hide)\n }\n\n // Add deselect onclick event\n deselect.onclick = (e: Event) => {\n e.stopPropagation()\n\n // Dont do anything if disabled\n if (this.settings.disabled) {\n return\n }\n\n if (this.settings.isMultiple && this.isAtMinSelected()) {\n return\n }\n\n // By Default we will delete\n let shouldDelete = true\n const before = this.store.getSelectedOptions()\n let after = [] as Option[]\n let newSelectedIds: string[] | string = ''\n\n if (this.settings.isMultiple) {\n const min = this.settings.minSelected\n const currentIds = this.store.getSelected()\n\n if (min > 0 && currentIds.length > min) {\n newSelectedIds = this.getMinimumSelectionIds()\n after = before.filter((o) => newSelectedIds.includes(o.id))\n } else if (min <= 0) {\n newSelectedIds = []\n } else {\n return\n }\n }\n\n // Add beforeChange callback\n if (this.callbacks.beforeChange) {\n shouldDelete = this.callbacks.beforeChange(after, before) === true\n }\n\n if (shouldDelete) {\n if (this.settings.isMultiple) {\n this.callbacks.setSelected(newSelectedIds, false)\n this.updateDeselectAll()\n } else {\n // Get first option and set it as selected\n const firstOption = this.store.getFirstOption()\n const id = firstOption ? firstOption.id : ''\n\n this.callbacks.setSelected(id, false)\n }\n\n // Check if we need to close the dropdown\n if (this.settings.closeOnSelect) {\n this.requestClose('deselect', { selectionChanged: true })\n }\n\n // Run afterChange callback\n if (this.callbacks.afterChange) {\n this.callbacks.afterChange(this.store.getSelectedOptions())\n }\n }\n }\n\n deselect.onkeydown = (e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n deselect.click()\n }\n }\n\n // Add deselect svg\n const deselectSvg = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'svg'\n )\n deselectSvg.setAttribute('viewBox', '0 0 100 100')\n const deselectPath = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n deselectPath.setAttribute('d', this.classes.deselectPath)\n deselectSvg.appendChild(deselectPath)\n deselect.appendChild(deselectSvg)\n main.appendChild(deselect)\n\n // Add arrow\n const arrow = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n this.addClasses(arrow, this.classes.arrow)\n arrow.setAttribute('viewBox', '0 0 100 100')\n const arrowPath = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n arrowPath.setAttribute('d', this.classes.arrowClose)\n if (this.settings.alwaysOpen) {\n this.addClasses(arrow, this.classes.hide)\n }\n arrow.appendChild(arrowPath)\n main.appendChild(arrow)\n\n return {\n main: main,\n values: values,\n deselect: {\n main: deselect,\n svg: deselectSvg,\n path: deselectPath\n },\n arrow: {\n main: arrow,\n path: arrowPath\n }\n }\n }\n\n public mainFocus(eventType: string | null): void {\n // Trigger focus but dont scroll to it\n // Need for prevent refocus the element if event is not keyboard event.\n // For example if event is mouse click or tachpad click this condition prevent refocus on element\n // because click by mouse change focus position and not need return focus to element.\n if (eventType !== 'click') {\n this.main.main.focus({ preventScroll: true })\n }\n }\n\n public placeholder(): HTMLDivElement {\n // Figure out if there is a placeholder option\n const placeholderOption = this.store.filter(\n (o) => o.placeholder,\n false,\n false\n ) as Option[]\n\n // If there is a placeholder option use that\n // If placeholder has an html value, use that\n // If placeholder has a text, use that\n // If nothing is set, use the placeholder text\n let placeholderText = this.settings.placeholderText\n if (placeholderOption.length) {\n if (placeholderOption[0].html !== '') {\n placeholderText = placeholderOption[0].html\n } else if (placeholderOption[0].text !== '') {\n placeholderText = placeholderOption[0].text\n }\n }\n\n // Create placeholder div\n const placeholder = document.createElement('div')\n this.addClasses(placeholder, this.classes.placeholder)\n placeholder.innerHTML = placeholderText\n return placeholder\n }\n\n // Get selected values and append to multiSelected values container\n // and remove those who shouldnt exist\n public renderValues(): void {\n // If single select set placeholder or selected value\n if (!this.settings.isMultiple) {\n this.renderSingleValue()\n return\n }\n\n this.renderMultipleValues()\n\n this.updateDeselectAll()\n }\n\n private renderSingleValue(): void {\n const selected = this.store.filter((o: Option): boolean => {\n return o.selected && !o.placeholder\n }, false, false) as Option[]\n const selectedSingle = selected.length > 0 ? selected[0] : null\n\n // If nothing is seleected use settings placeholder text\n if (!selectedSingle) {\n this.main.values.innerHTML = this.placeholder().outerHTML\n } else {\n // Create single value container\n const singleValue = document.createElement('div')\n this.addClasses(singleValue, this.classes.single)\n if (selectedSingle.html) {\n singleValue.innerHTML = selectedSingle.html\n } else {\n singleValue.innerText = selectedSingle.text\n }\n\n // If there is a selected value, set a single div\n this.main.values.innerHTML = singleValue.outerHTML\n }\n\n // If allowDeselect is false or selected value is empty just hide deselect\n if (!this.settings.allowDeselect || !selected.length) {\n this.addClasses(this.main.deselect.main, this.classes.hide)\n } else {\n this.removeClasses(this.main.deselect.main, this.classes.hide)\n }\n }\n\n private renderMultipleValues(): void {\n // Get various pieces of data\n let currentNodes = this.main.values.childNodes as NodeListOf<HTMLDivElement>\n let selectedOptions = this.store.filter((opt: Option) => {\n // Only grab options that are selected and display is true\n return opt.selected && opt.display\n }, false, false) as Option[]\n\n // If selectedOptions is empty set placeholder\n if (selectedOptions.length === 0) {\n this.main.values.innerHTML = this.placeholder().outerHTML\n return\n } else {\n // If there is a placeholder, remove it\n const placeholder = this.main.values.querySelector(\n '.' + this.classes.getFirst('placeholder')\n )\n if (placeholder) {\n placeholder.remove()\n }\n }\n\n // If multiString is enabled, render a single text element containing the\n // selected values joined by commas instead of individual value pills.\n // CSS truncates the text with an ellipsis when it exceeds the container width.\n if (this.settings.multiString) {\n let commaOptions = selectedOptions\n if (this.settings.keepOrder) {\n commaOptions = this.store.selectedOrderOptions(commaOptions)\n }\n\n const commaValue = document.createElement('div')\n this.addClasses(commaValue, this.classes.multiString)\n commaValue.textContent = commaOptions\n .map((o: Option) => o.text)\n .join(', ')\n\n if (this.settings.showOptionTooltips) {\n commaValue.setAttribute('title', commaValue.textContent)\n }\n\n this.main.values.innerHTML = commaValue.outerHTML\n return\n }\n\n // If selectedOptions is greater than maxItems, set maxValuesMessage\n if (selectedOptions.length > this.settings.maxValuesShown) {\n // Creating the element that shows the number of selected items\n const singleValue = document.createElement('div')\n this.addClasses(singleValue, this.classes.max)\n singleValue.textContent = this.settings.maxValuesMessage.replace(\n '{number}',\n selectedOptions.length.toString()\n )\n\n // If there is a selected value, set a single div\n this.main.values.innerHTML = singleValue.outerHTML\n return\n } else {\n // If there is a message, remove it\n const maxValuesMessage = this.main.values.querySelector(\n '.' + this.classes.getFirst('max')\n )\n if (maxValuesMessage) {\n maxValuesMessage.remove()\n }\n }\n\n // Lets check for data selected order\n if (this.settings.keepOrder) {\n selectedOptions = this.store.selectedOrderOptions(selectedOptions)\n }\n\n // Loop through currentNodes and only include ones that are not in selectedIDs\n let removeNodes: HTMLDivElement[] = []\n for (let i = 0; i < currentNodes.length; i++) {\n const node = currentNodes[i]\n const id = node.getAttribute('data-id')\n if (id) {\n // Check if id is in selectedOptions\n const found = selectedOptions.filter((opt: Option) => {\n return opt.id === id\n }, false)\n\n // If not found, add to removeNodes\n if (!found.length) {\n removeNodes.push(node)\n }\n }\n }\n\n const animationDuration = getAnimationTimeout(\n this.content.main,\n this.settings.timeoutDelay\n )\n\n // Loop through and remove\n for (const n of removeNodes) {\n this.addClasses(n, this.classes.valueOut)\n void waitForAnimationEnd(n, 'ss-valueOut', animationDuration).then(() => {\n if (this.main.values.hasChildNodes() && this.main.values.contains(n)) {\n this.main.values.removeChild(n)\n }\n })\n }\n\n // Add values that dont currently exist\n currentNodes = this.main.values.childNodes as NodeListOf<HTMLDivElement>\n for (let d = 0; d < selectedOptions.length; d++) {\n let shouldAdd = true\n for (let i = 0; i < currentNodes.length; i++) {\n if (selectedOptions[d].id === String(currentNodes[i].dataset.id)) {\n shouldAdd = false\n }\n }\n\n // If shouldAdd, insertAdjacentElement it to the values container in the order of the selectedOptions\n if (shouldAdd) {\n // If keepOrder is true, we will just append it to the end\n if (this.settings.keepOrder) {\n this.main.values.appendChild(this.multipleValue(selectedOptions[d]))\n } else {\n // else we will insert it in the order of the selectedOptions\n if (currentNodes.length === 0) {\n this.main.values.appendChild(this.multipleValue(selectedOptions[d]))\n } else if (d === 0) {\n this.main.values.insertBefore(\n this.multipleValue(selectedOptions[d]),\n currentNodes[d]\n )\n } else {\n currentNodes[d - 1].insertAdjacentElement(\n 'afterend',\n this.multipleValue(selectedOptions[d])\n )\n }\n }\n }\n }\n\n this.updateMultipleValueDeleteVisibility()\n }\n\n private isAtMinSelected(): boolean {\n return (\n this.settings.isMultiple &&\n this.settings.minSelected > 0 &&\n this.store.getSelectedOptions().length <= this.settings.minSelected\n )\n }\n\n private getMinimumSelectionIds(): string[] {\n let selected = this.store.getSelectedOptions()\n if (this.settings.keepOrder) {\n selected = this.store.selectedOrderOptions(selected)\n }\n\n return selected\n .slice(0, this.settings.minSelected)\n .map((option) => option.id)\n }\n\n private updateMultipleValueDeleteVisibility(): void {\n if (!this.settings.isMultiple || this.settings.multiString) {\n return\n }\n\n const canRemove = !this.isAtMinSelected()\n const deleteButtons = this.main.values.querySelectorAll(\n '.' + this.classes.getFirst('valueDelete')\n )\n\n for (const deleteButton of deleteButtons) {\n if (canRemove) {\n this.removeClasses(deleteButton as HTMLElement, this.classes.hide)\n } else {\n this.addClasses(deleteButton as HTMLElement, this.classes.hide)\n }\n }\n }\n\n public multipleValue(option: Option): HTMLDivElement {\n const value = document.createElement('div')\n this.addClasses(value, this.classes.value)\n value.dataset.id = option.id\n\n const text = document.createElement('div')\n this.addClasses(text, this.classes.valueText)\n text.textContent = option.text // For multiple values always use text\n value.appendChild(text)\n\n // Only add deletion if the option is not mandatory\n if (!option.mandatory) {\n // Create delete div element\n const deleteDiv = document.createElement('div')\n this.addClasses(deleteDiv, this.classes.valueDelete)\n deleteDiv.setAttribute('tabindex', '0') // Make the div focusable for tab navigation\n deleteDiv.setAttribute('role', 'button')\n deleteDiv.setAttribute(\n 'aria-label',\n `${this.settings.removeText} ${option.text}`\n )\n\n if (this.isAtMinSelected()) {\n this.addClasses(deleteDiv, this.classes.hide)\n }\n\n // Add delete onclick event\n deleteDiv.onclick = (e: Event) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Dont do anything if disabled\n if (this.settings.disabled) {\n return\n }\n\n // By Default we will delete\n let shouldDelete = true\n const before = this.store.getSelectedOptions()\n const after = before.filter((o) => {\n return o.selected && o.id !== option.id\n }, true)\n\n // Check if minSelected is set and if after length so, return\n if (\n this.settings.minSelected &&\n after.length < this.settings.minSelected\n ) {\n return\n }\n\n // If there is a beforeDeselect function run it\n if (this.callbacks.beforeChange) {\n shouldDelete = this.callbacks.beforeChange(after, before) === true\n }\n\n if (shouldDelete) {\n // Loop through after and append ids to a variable called selected\n let selectedIds: string[] = []\n for (const o of after) {\n if (o instanceof Optgroup) {\n for (const c of o.options) {\n if (c.id) {\n selectedIds.push(c.id)\n }\n }\n }\n\n if (o instanceof Option) {\n selectedIds.push(o.id)\n }\n }\n this.callbacks.setSelected(selectedIds, false)\n\n // Check if we need to close the dropdown\n if (this.settings.closeOnSelect) {\n this.requestClose('deselect', { selectionChanged: true })\n }\n\n // Run afterChange callback\n if (this.callbacks.afterChange) {\n this.callbacks.afterChange(after)\n }\n\n this.updateDeselectAll()\n this.updateMultipleValueDeleteVisibility()\n }\n }\n\n // Add delete svg\n const deleteSvg = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'svg'\n )\n deleteSvg.setAttribute('viewBox', '0 0 100 100')\n const deletePath = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n deletePath.setAttribute('d', this.classes.optionDelete)\n deleteSvg.appendChild(deletePath)\n deleteDiv.appendChild(deleteSvg)\n\n value.appendChild(deleteDiv)\n\n // Add keydown event listener for keyboard navigation (Enter key)\n deleteDiv.onkeydown = (e) => {\n if (e.key === 'Enter') {\n deleteDiv.click() // Trigger the click event when Enter is pressed\n }\n }\n }\n\n return value\n }\n\n public contentDiv(): Content {\n const main = document.createElement('div')\n\n // Add id to data-id\n main.dataset.id = this.settings.id\n // main.id = this.settings.id + '-content' // Remove for now as it is not needed and add duplicate id errors\n\n // Add search\n const search = this.searchDiv()\n main.appendChild(search.main)\n\n // Screen reader announcements for search result updates\n const status = document.createElement('div')\n this.addClasses(status, this.classes.status)\n status.setAttribute('aria-live', 'polite')\n status.setAttribute('aria-atomic', 'true')\n status.setAttribute('role', 'status')\n main.appendChild(status)\n\n // Add list\n const list = this.listDiv()\n main.appendChild(list)\n\n return {\n main: main,\n search: search,\n status: status,\n list: list\n }\n }\n\n private announce(message: string): void {\n if (!this.settings.showSearch) {\n return\n }\n\n this.content.status.textContent = message\n }\n\n public moveContent(): void {\n if (this.isModalViewActive()) {\n return\n }\n\n if (this.settings.contentPosition === 'relative') {\n this.moveContentBelow()\n return\n }\n\n if (this.settings.openPosition === 'down') {\n this.moveContentBelow()\n return\n } else if (this.settings.openPosition === 'up') {\n this.moveContentAbove()\n return\n }\n\n if (this.putContent() === 'up') {\n this.moveContentAbove()\n } else {\n this.moveContentBelow()\n }\n }\n\n /** Track trigger/content layout changes and reposition the dropdown panel. */\n public startPositionTracking(): void {\n if (this.settings.contentPosition !== 'absolute' || this.isModalViewActive()) {\n return\n }\n\n this.stopPositionTracking()\n\n if (typeof ResizeObserver === 'undefined') {\n return\n }\n\n this.positionObserver = new ResizeObserver(() => {\n if (!this.settings.isOpen) {\n return\n }\n\n cancelAnimationFrame(this.positionObserverRaf)\n this.positionObserverRaf = requestAnimationFrame(() => {\n this.moveContent()\n })\n })\n\n this.observePositionTargets()\n }\n\n public stopPositionTracking(): void {\n cancelAnimationFrame(this.positionObserverRaf)\n this.positionObserver?.disconnect()\n this.positionObserver = null\n this.cancelOverflowShift()\n }\n\n private observePositionTargets(): void {\n if (!this.positionObserver) {\n return\n }\n\n const observed = new Set<Element>()\n const observe = (el: Element | null): void => {\n if (!el || observed.has(el)) {\n return\n }\n\n observed.add(el)\n this.positionObserver!.observe(el)\n }\n\n observe(this.main.main)\n // Do not observe content — our own overflow/position updates resize the panel\n // and would re-enter moveContent() causing horizontal jitter at the viewport edge.\n\n let parent: HTMLElement | null = this.main.main.parentElement\n const stopAt = this.settings.contentLocation\n\n for (let depth = 0; parent && depth < 8; depth++) {\n observe(parent)\n if (parent === stopAt) {\n break\n }\n parent = parent.parentElement\n }\n }\n\n public searchDiv(): Search {\n const main = document.createElement('div')\n const input = document.createElement('input')\n const addable = document.createElement('div')\n this.addClasses(main, this.classes.search)\n\n // Setup search return object\n const searchReturn: Search = {\n main,\n input\n }\n\n // We still want the search to be tabable but not shown\n if (!this.settings.showSearch) {\n this.addClasses(main, this.classes.hide)\n input.readOnly = true\n }\n\n input.type = 'search'\n input.placeholder = this.settings.searchPlaceholder\n input.tabIndex = -1\n input.setAttribute('aria-label', this.settings.searchPlaceholder)\n input.setAttribute('aria-autocomplete', 'list')\n input.setAttribute('autocapitalize', 'off')\n input.setAttribute('autocomplete', 'off')\n input.setAttribute('autocorrect', 'off')\n // Hide from screen readers by default (shown when opened)\n input.setAttribute('aria-hidden', 'true')\n\n input.oninput = debounce((e: Event) => {\n this.callbacks.search((e.target as HTMLInputElement).value)\n }, 100)\n\n // Deal with keyboard events on search input field\n input.onkeydown = (e: KeyboardEvent): boolean => {\n // Convert above if else statemets to switch\n switch (e.key) {\n case 'ArrowUp':\n case 'ArrowDown':\n e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up')\n return false\n case 'Tab':\n // When tabbing close the dropdown\n // which will also focus on main div\n // and then continuing normal tabbing\n this.requestClose('tab')\n return true // Continue doing normal tabbing\n case 'Escape':\n this.requestClose('escape')\n return false\n case 'Enter':\n // Check if there's a highlighted option first\n const highlightedEnter = this.content.list.querySelector(\n '.' + this.classes.getFirst('highlighted')\n ) as HTMLDivElement\n if (highlightedEnter) {\n // If an option is highlighted, select it (even if addable is enabled)\n highlightedEnter.click()\n return false\n } else if (this.callbacks.addable) {\n // If no option is highlighted and addable is enabled, add new item\n addable.click()\n return false\n }\n return true\n }\n\n return true // Allow normal typing\n }\n\n main.appendChild(input)\n\n // If addable is enabled, add the addable div\n if (this.callbacks.addable) {\n // Add main class\n this.addClasses(addable, this.classes.addable)\n\n // Add svg icon\n const plus = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n plus.setAttribute('viewBox', '0 0 100 100')\n const plusPath = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n plusPath.setAttribute('d', this.classes.addablePath)\n plus.appendChild(plusPath)\n addable.appendChild(plus)\n\n // Add click event to addable div\n addable.onclick = (e: Event) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Do nothing if addable is not set\n if (!this.callbacks.addable) {\n return\n }\n\n // Grab input value\n const inputValue = this.content.search.input.value.trim()\n if (inputValue === '') {\n this.content.search.input.focus()\n return\n }\n\n // Run finish will be ran at the end of the addable function.\n // Reason its in a function is so we can run it after the\n // addable function is done for promise based addables\n const runFinish = (oo: Partial<Option>) => {\n let newOption = new Option(oo)\n\n // Call addOption to add the new option\n this.callbacks.addOption(newOption)\n\n // set selected value for single and multiple\n if (this.settings.isMultiple) {\n let ids = this.store.getSelected()\n ids.push(newOption.id)\n this.callbacks.setSelected(ids, true)\n } else {\n this.callbacks.setSelected([newOption.id], true)\n }\n\n // Clear search\n this.callbacks.search('')\n\n // Close it only if closeOnSelect = true\n if (this.settings.closeOnSelect) {\n const animationDuration = getAnimationDuration(this.content.main)\n setTimeout(() => {\n this.requestClose('select', { selectionChanged: true })\n }, animationDuration)\n }\n }\n\n // Call addable callback\n const addableValue = this.callbacks.addable(inputValue)\n\n // If addableValue is false, undefined or null, do nothing\n if (\n addableValue === false ||\n addableValue === undefined ||\n addableValue === null\n ) {\n return\n }\n\n // If addableValue is a promise, wait for it to resolve\n if (addableValue instanceof Promise) {\n addableValue.then((value) => {\n if (typeof value === 'string') {\n runFinish({\n text: value,\n value: value\n })\n } else if (addableValue instanceof Error) {\n this.renderError(addableValue.message)\n } else {\n runFinish(value)\n }\n })\n } else if (typeof addableValue === 'string') {\n runFinish({\n text: addableValue,\n value: addableValue\n })\n } else if (addableValue instanceof Error) {\n this.renderError(addableValue.message)\n } else {\n runFinish(addableValue)\n }\n\n return\n }\n main.appendChild(addable)\n\n // Add the addable to the search return\n searchReturn.addable = {\n main: addable,\n svg: plus,\n path: plusPath\n }\n }\n\n return searchReturn\n }\n\n public searchFocus(): void {\n this.content.search.input.focus({ preventScroll: true })\n }\n\n public getOptions(\n notPlaceholder = false,\n notDisabled = false,\n notHidden = false\n ): HTMLDivElement[] {\n // Put together query string\n let query = '.' + this.classes.getFirst('option')\n if (notPlaceholder) {\n query += ':not(.' + this.classes.getFirst('placeholder') + ')'\n }\n if (notDisabled) {\n query += ':not(.' + this.classes.getFirst('disabled') + ')'\n }\n if (notHidden) {\n query += ':not(.' + this.classes.getFirst('hide') + ')'\n }\n\n return Array.from(this.content.list.querySelectorAll(query))\n }\n\n // highlightUp is used to highlight the previous option in the list\n public highlight(dir: 'up' | 'down'): void {\n // Get full list of options in list\n const options = this.getOptions(true, true, true)\n\n // If there are no options, do nothing\n if (options.length === 0) {\n return\n }\n\n // If length is 1, highlight it\n if (options.length === 1) {\n // Check if option doesnt already have highlighted class\n if (\n !options[0].classList.contains(this.classes.getFirst('highlighted'))\n ) {\n this.addClasses(options[0], this.classes.highlighted)\n return\n }\n }\n\n // Loop through options and see if there are no highlighted ones\n let highlighted = false\n for (const o of options) {\n if (o.classList.contains(this.classes.getFirst('highlighted'))) {\n highlighted = true\n }\n }\n\n // If no highlighted, see if any are selected and if so highlight selected first one\n if (!highlighted) {\n for (const o of options) {\n if (o.classList.contains(this.classes.getFirst('selected'))) {\n this.addClasses(o, this.classes.highlighted)\n break\n }\n }\n }\n\n // Loop through options and find the highlighted one\n for (let i = 0; i < options.length; i++) {\n // Found highlighted option\n if (options[i].classList.contains(this.classes.getFirst('highlighted'))) {\n const prevOption = options[i]\n // Remove highlighted class from current one\n this.removeClasses(prevOption, this.classes.highlighted)\n\n // If previous option has parent classes ss-optgroup with ss-open then click it\n const prevParent = prevOption.parentElement\n if (\n prevParent &&\n prevParent.classList.contains(this.classes.getFirst('mainOpen'))\n ) {\n const optgroupLabel = prevParent.querySelector(\n '.' + this.classes.getFirst('optgroupLabel')\n ) as HTMLDivElement\n if (optgroupLabel) {\n optgroupLabel.click()\n }\n }\n\n // Highlight the next one\n let selectOption =\n options[\n dir === 'down'\n ? i + 1 < options.length\n ? i + 1\n : 0\n : i - 1 >= 0\n ? i - 1\n : options.length - 1\n ]\n this.addClasses(selectOption, this.classes.highlighted)\n this.ensureElementInView(this.content.list, selectOption)\n\n // Update aria-activedescendant for screen readers\n if (selectOption.id) {\n this.main.main.setAttribute('aria-activedescendant', selectOption.id)\n }\n\n // If selected option has parent classes ss-optgroup with ss-close then click it\n const selectParent = selectOption.parentElement\n if (\n selectParent &&\n selectParent.classList.contains(this.classes.getFirst('close'))\n ) {\n const optgroupLabel = selectParent.querySelector(\n '.' + this.classes.getFirst('optgroupLabel')\n ) as HTMLDivElement\n if (optgroupLabel) {\n optgroupLabel.click()\n }\n }\n\n return\n }\n }\n\n // If we get here, there is no highlighted option\n // So we will highlight the first or last based upon direction\n const firstHighlight = options[dir === 'down' ? 0 : options.length - 1]\n this.addClasses(firstHighlight, this.classes.highlighted)\n\n // Update aria-activedescendant for screen readers\n if (firstHighlight.id) {\n this.main.main.setAttribute('aria-activedescendant', firstHighlight.id)\n }\n\n // Scroll to highlighted one\n this.ensureElementInView(this.content.list, firstHighlight)\n }\n\n // Create main container that options will reside\n public listDiv(): HTMLDivElement {\n const options = document.createElement('div')\n this.addClasses(options, this.classes.list)\n\n // Add id for ARIA controls reference\n const listId = this.settings.id + '-list'\n options.id = listId\n options.dataset.id = listId\n\n return options\n }\n\n public renderError(error: string) {\n this.optionsListIsFullData = false\n // Clear out innerHtml\n this.content.list.innerHTML = ''\n\n const errorDiv = document.createElement('div')\n this.addClasses(errorDiv, this.classes.error)\n errorDiv.textContent = error\n this.content.list.appendChild(errorDiv)\n }\n\n public renderSearching() {\n this.optionsListIsFullData = false\n // Clear out innerHtml\n this.content.list.innerHTML = ''\n\n const searchingDiv = document.createElement('div')\n this.addClasses(searchingDiv, this.classes.searching)\n searchingDiv.textContent = this.settings.searchingText\n this.content.list.appendChild(searchingDiv)\n this.announce(this.settings.searchingText)\n }\n\n // Take in data and add options to\n public renderOptions(data: (Option | Optgroup)[]): void {\n this.lastSearchFilterTerm = ''\n this.lastRenderedOptions = data\n .map((o) =>\n o instanceof Option ? [o] : o.options.map((po) => new Option(po))\n )\n .flat()\n\n // Clear out innerHtml\n this.content.list.innerHTML = ''\n\n // If no results show no results text\n if (data.length === 0) {\n this.optionsListIsFullData = false\n const noResults = document.createElement('div')\n this.addClasses(noResults, this.classes.search)\n\n //\n if (this.callbacks.addable) {\n const addableMessage = this.settings.addableText.replace(\n '{value}',\n this.content.search.input.value\n )\n noResults.innerHTML = addableMessage\n this.announce(addableMessage)\n } else {\n noResults.innerHTML = this.settings.searchText\n this.announce(this.settings.searchText)\n }\n this.content.list.appendChild(noResults)\n return\n }\n\n // If settings has allowDeselect and isSingle, add empty placeholder in the event they want to deselect\n if (this.settings.allowDeselect && !this.settings.isMultiple) {\n // Check if store options have a placeholder\n const placeholderOption = this.store.filter(\n (o) => o.placeholder,\n false,\n false\n ) as Option[]\n if (!placeholderOption.length) {\n this.store.addOption(\n new Option({\n text: '',\n value: '',\n selected: false,\n placeholder: true\n }),\n true\n )\n }\n }\n\n // Append individual options to div container\n const fragment = document.createDocumentFragment()\n for (const d of data) {\n // Create optgroup\n if (d instanceof Optgroup) {\n // Create optgroup\n const optgroupEl = document.createElement('div')\n this.addClasses(optgroupEl, this.classes.optgroup)\n\n // Create label\n const optgroupLabel = document.createElement('div')\n this.addClasses(optgroupLabel, this.classes.optgroupLabel)\n optgroupEl.appendChild(optgroupLabel)\n\n // Create label text div element\n const optgroupLabelText = document.createElement('div')\n this.addClasses(optgroupLabelText, this.classes.optgroupLabelText)\n optgroupLabelText.textContent = d.label\n optgroupLabel.appendChild(optgroupLabelText)\n\n // Create options container\n const optgroupActions = document.createElement('div')\n this.addClasses(optgroupActions, this.classes.optgroupActions)\n optgroupLabel.appendChild(optgroupActions)\n\n // If selectByGroup is true and isMultiple then add click event to label\n if (this.settings.isMultiple && d.selectAll) {\n // Create new div to hold a checkbox svg\n const selectAll = document.createElement('div')\n this.addClasses(selectAll, this.classes.optgroupSelectAll)\n\n // Check options and if all are selected, if so add class selected\n const allSelected = this.isOptgroupAllSelected(d.options as Option[])\n\n // Add class if all selected\n if (allSelected) {\n this.addClasses(selectAll, this.classes.selected)\n }\n\n // Add select all text span\n const selectAllLabel = document.createElement('span')\n selectAllLabel.textContent = this.optgroupSelectAllLabel(allSelected)\n selectAll.appendChild(selectAllLabel)\n\n // Create new svg for checkbox\n const selectAllSvg = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'svg'\n )\n selectAllSvg.setAttribute('viewBox', '0 0 100 100')\n selectAll.appendChild(selectAllSvg)\n\n // Create new path for box\n const selectAllBox = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n selectAllBox.setAttribute('d', this.classes.optgroupSelectAllBox)\n selectAllSvg.appendChild(selectAllBox)\n\n // Create new path for check\n const selectAllCheck = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n selectAllCheck.setAttribute('d', this.classes.optgroupSelectAllCheck)\n selectAllSvg.appendChild(selectAllCheck)\n\n // Add click event listener to select all\n selectAll.addEventListener('click', (e: MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Get the store current selected values\n const currentSelected = this.store.getSelected()\n const allSelectedNow = this.isOptgroupAllSelected(\n d.options as Option[],\n new Set(currentSelected)\n )\n\n // If all selected, remove all options from selected\n if (allSelectedNow) {\n // Put together new list minus all options in this optgroup\n const newSelected = currentSelected.filter((s) => {\n for (const o of d.options) {\n if (s === o.id) {\n return false\n }\n }\n\n return true\n })\n\n this.callbacks.setSelected(newSelected, true)\n return\n } else {\n // Put together new list with all options in this optgroup\n let optionIds = d.options\n .map((o) => o.id)\n .filter((id) => id !== undefined)\n const newSelected = currentSelected.concat(optionIds)\n\n // Loop through options and if they don't exist in the store\n // run addOption callback\n for (const o of d.options) {\n if (o.id && !this.store.getOptionByID(o.id)) {\n this.callbacks.addOption(new Option(o))\n }\n }\n\n this.callbacks.setSelected(newSelected, true)\n return\n }\n })\n\n // Append select all to label\n optgroupActions.appendChild(selectAll)\n }\n\n // If optgroup has collapsable\n if (d.closable !== 'off') {\n // Create new div to hold a checkbox svg\n const optgroupClosable = document.createElement('div')\n this.addClasses(optgroupClosable, this.classes.optgroupClosable)\n\n // Create svg arrow\n const optgroupClosableSvg = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'svg'\n )\n optgroupClosableSvg.setAttribute('viewBox', '0 0 100 100')\n this.addClasses(optgroupClosableSvg, this.classes.arrow)\n optgroupClosable.appendChild(optgroupClosableSvg)\n\n // Create new path for arrow\n const optgroupClosableArrow = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n )\n optgroupClosableSvg.appendChild(optgroupClosableArrow)\n\n // If any options are selected or someone is searching, set optgroup to open\n if (\n d.options.some((o) => o.selected) ||\n this.content.search.input.value.trim() !== ''\n ) {\n this.addClasses(optgroupClosable, this.classes.mainOpen)\n optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen)\n } else if (d.closable === 'open') {\n this.addClasses(optgroupEl, this.classes.mainOpen)\n optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen)\n } else if (d.closable === 'close') {\n this.addClasses(optgroupEl, this.classes.close)\n optgroupClosableArrow.setAttribute('d', this.classes.arrowClose)\n }\n\n // Add click event listener to close\n optgroupLabel.addEventListener('click', (e: MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n\n const isOpen = this.isClosableOptgroupOpen(\n optgroupEl,\n optgroupClosable\n )\n\n if (!isOpen) {\n this.closeOtherClosableOptgroups(optgroupEl)\n this.removeClasses(optgroupEl, this.classes.close)\n this.removeClasses(optgroupClosable, this.classes.mainOpen)\n this.addClasses(optgroupEl, this.classes.mainOpen)\n optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen)\n } else {\n this.removeClasses(optgroupEl, this.classes.mainOpen)\n this.removeClasses(optgroupClosable, this.classes.mainOpen)\n this.addClasses(optgroupEl, this.classes.close)\n optgroupClosableArrow.setAttribute('d', this.classes.arrowClose)\n }\n })\n\n // Append close to label\n optgroupActions.appendChild(optgroupClosable)\n }\n\n // Add optgroup label\n optgroupEl.appendChild(optgroupLabel)\n\n // Loop through options\n for (const option of d.options) {\n optgroupEl.appendChild(this.option(new Option(option)))\n fragment.appendChild(optgroupEl)\n }\n }\n\n // Create option\n if (d instanceof Option) {\n fragment.appendChild(this.option(d as Option))\n }\n }\n\n // Append fragment to list\n this.content.list.appendChild(fragment)\n this.setOptionsListFullData(data)\n this.announce(\n this.settings.resultsText.replace(\n '{count}',\n String(this.lastRenderedOptions.length)\n )\n )\n }\n\n /** True when the list DOM contains every store option (local search can show/hide in place). */\n public canFilterOptionsInPlace(): boolean {\n if (!this.optionsListIsFullData) {\n return false\n }\n\n return (\n this.content.list.querySelector(\n '.' + this.classes.getFirst('option')\n ) !== null\n )\n }\n\n public resetSearchFilterState(): void {\n this.lastSearchFilterTerm = ''\n }\n\n /** Filter visible options by search without rebuilding the list. */\n public filterOptionsInPlace(\n search: string,\n searchFilter: (opt: Option, search: string) => boolean\n ): void {\n const searchTrim = search.trim()\n if (searchTrim === this.lastSearchFilterTerm) {\n return\n }\n this.lastSearchFilterTerm = searchTrim\n\n const visibleOptions: Option[] = []\n const optionEls = this.content.list.querySelectorAll(\n '.' + this.classes.getFirst('option')\n ) as NodeListOf<HTMLDivElement>\n\n for (const optionEl of optionEls) {\n const id = optionEl.dataset.id\n if (!id) {\n continue\n }\n\n const storeOption = this.store.getOptionByID(id)\n if (!storeOption) {\n continue\n }\n\n const isPermanentlyHidden =\n storeOption.placeholder ||\n !storeOption.display ||\n (storeOption.selected && this.settings.hideSelected)\n\n const matchesSearch = searchFilter(storeOption, searchTrim)\n\n if (isPermanentlyHidden || !matchesSearch) {\n this.addClasses(optionEl, this.classes.hide)\n this.removeClasses(optionEl, this.classes.highlighted)\n } else {\n this.removeClasses(optionEl, this.classes.hide)\n this.setOptionElementContent(optionEl, storeOption, searchTrim)\n visibleOptions.push(storeOption)\n }\n\n if (storeOption.selected) {\n this.addClasses(optionEl, this.classes.selected)\n optionEl.setAttribute('aria-selected', 'true')\n } else {\n this.removeClasses(optionEl, this.classes.selected)\n optionEl.setAttribute('aria-selected', 'false')\n }\n }\n\n this.lastRenderedOptions = visibleOptions\n this.updateOptgroupVisibilityAfterSearch(searchTrim)\n\n if (visibleOptions.length === 0) {\n this.updateSearchResultsMessage(0, searchTrim)\n } else {\n this.removeListSearchMessage()\n this.announce(\n this.settings.resultsText.replace(\n '{count}',\n String(visibleOptions.length)\n )\n )\n }\n\n this.updateOptgroupSelectAllStates()\n }\n\n private setOptionsListFullData(data: (Option | Optgroup)[]): void {\n const storeOptions = this.store.getDataOptions(false)\n const renderedOptions = data\n .map((o) =>\n o instanceof Option ? [o] : o.options.map((po) => new Option(po))\n )\n .flat()\n\n if (renderedOptions.length !== storeOptions.length) {\n this.optionsListIsFullData = false\n return\n }\n\n const storeIds = new Set(storeOptions.map((o) => o.id))\n this.optionsListIsFullData = renderedOptions.every((o) =>\n storeIds.has(o.id)\n )\n }\n\n private isClosableOptgroupOpen(\n optgroupEl: HTMLElement,\n optgroupClosable: HTMLElement\n ): boolean {\n if (optgroupEl.classList.contains(this.classes.getFirst('close'))) {\n return false\n }\n\n return (\n optgroupEl.classList.contains(this.classes.getFirst('mainOpen')) ||\n optgroupClosable.classList.contains(this.classes.getFirst('mainOpen'))\n )\n }\n\n private closeClosableOptgroup(optgroupEl: HTMLElement): void {\n const closable = optgroupEl.querySelector(\n '.' + this.classes.getFirst('optgroupClosable')\n ) as HTMLElement | null\n if (!closable) {\n return\n }\n\n if (optgroupEl.classList.contains(this.classes.getFirst('close'))) {\n return\n }\n\n this.removeClasses(optgroupEl, this.classes.mainOpen)\n this.removeClasses(closable, this.classes.mainOpen)\n this.addClasses(optgroupEl, this.classes.close)\n\n const arrow = closable.querySelector('path')\n if (arrow) {\n arrow.setAttribute('d', this.classes.arrowClose)\n }\n }\n\n private closeOtherClosableOptgroups(exceptOptgroupEl: HTMLElement): void {\n const optgroups = this.content.list.querySelectorAll(\n '.' + this.classes.getFirst('optgroup')\n )\n\n for (const optgroupEl of optgroups) {\n if (optgroupEl === exceptOptgroupEl) {\n continue\n }\n\n this.closeClosableOptgroup(optgroupEl as HTMLElement)\n }\n }\n\n private updateOptgroupVisibilityAfterSearch(searchTrim: string): void {\n const optgroups = this.content.list.querySelectorAll(\n '.' + this.classes.getFirst('optgroup')\n )\n\n for (const optgroupEl of optgroups) {\n const optionEls = optgroupEl.querySelectorAll(\n '.' + this.classes.getFirst('option')\n ) as NodeListOf<HTMLDivElement>\n\n let hasVisibleOption = false\n for (const optionEl of optionEls) {\n if (!optionEl.classList.contains(this.classes.getFirst('hide'))) {\n hasVisibleOption = true\n break\n }\n }\n\n if (!hasVisibleOption) {\n this.addClasses(optgroupEl as HTMLDivElement, this.classes.hide)\n continue\n }\n\n this.removeClasses(optgroupEl as HTMLDivElement, this.classes.hide)\n\n if (searchTrim !== '') {\n this.removeClasses(optgroupEl as HTMLDivElement, this.classes.close)\n this.addClasses(optgroupEl as HTMLDivElement, this.classes.mainOpen)\n }\n }\n }\n\n private updateSearchResultsMessage(\n visibleCount: number,\n searchTrim: string\n ): void {\n this.removeListSearchMessage()\n\n if (visibleCount > 0) {\n return\n }\n\n const noResults = document.createElement('div')\n this.addClasses(noResults, this.classes.search)\n\n if (this.callbacks.addable) {\n const addableMessage = this.settings.addableText.replace(\n '{value}',\n searchTrim\n )\n noResults.innerHTML = addableMessage\n this.announce(addableMessage)\n } else {\n noResults.innerHTML = this.settings.searchText\n this.announce(this.settings.searchText)\n }\n\n this.content.list.appendChild(noResults)\n }\n\n private removeListSearchMessage(): void {\n const messages = this.content.list.querySelectorAll(\n '.' + this.classes.getFirst('search')\n )\n messages.forEach((message) => message.remove())\n }\n\n private setOptionElementContent(\n optionEl: HTMLDivElement,\n option: Option,\n search: string\n ): void {\n const searchTrim = search.trim()\n if (this.settings.searchHighlight && searchTrim !== '') {\n optionEl.innerHTML = this.highlightText(\n option.html !== '' ? option.html : option.text,\n searchTrim,\n this.classes.searchHighlighter\n )\n } else if (option.html !== '') {\n optionEl.innerHTML = option.html\n } else {\n optionEl.textContent = option.text\n }\n\n if (this.settings.showOptionTooltips && optionEl.textContent) {\n optionEl.setAttribute('title', optionEl.textContent)\n } else {\n optionEl.removeAttribute('title')\n }\n }\n\n /** True when option nodes exist in the list (selection can sync without re-searching). */\n public hasRenderedOptions(): boolean {\n return (\n this.content.list.querySelector(\n '.' + this.classes.getFirst('option')\n ) !== null\n )\n }\n\n /** True when the open list already has options and search is not filtering. */\n public canUpdateOptionSelectionInPlace(): boolean {\n if (this.content.search.input.value.trim() !== '') {\n return false\n }\n\n return this.hasRenderedOptions()\n }\n\n /** Sync selected/hidden state on existing option nodes without rebuilding the list. */\n public updateOptionSelection(): void {\n const selectedIds = new Set(this.store.getSelected())\n const optionEls = this.content.list.querySelectorAll(\n '.' + this.classes.getFirst('option')\n ) as NodeListOf<HTMLDivElement>\n\n let lastSelectedEl: HTMLDivElement | null = null\n\n for (const optionEl of optionEls) {\n const id = optionEl.dataset.id\n if (!id) {\n continue\n }\n\n const storeOption = this.store.getOptionByID(id)\n if (!storeOption) {\n continue\n }\n\n const isSelected = selectedIds.has(id)\n\n if (isSelected) {\n this.addClasses(optionEl, this.classes.selected)\n optionEl.setAttribute('aria-selected', 'true')\n lastSelectedEl = optionEl\n } else {\n this.removeClasses(optionEl, this.classes.selected)\n optionEl.setAttribute('aria-selected', 'false')\n }\n\n if (this.settings.hideSelected) {\n if (isSelected) {\n this.addClasses(optionEl, this.classes.hide)\n } else {\n this.removeClasses(optionEl, this.classes.hide)\n if (!storeOption.display) {\n this.addClasses(optionEl, this.classes.hide)\n }\n }\n }\n }\n\n if (!this.settings.isMultiple && lastSelectedEl) {\n this.main.main.setAttribute('aria-activedescendant', lastSelectedEl.id)\n } else if (!this.settings.isMultiple && selectedIds.size === 0) {\n this.main.main.removeAttribute('aria-activedescendant')\n }\n\n this.updateOptgroupSelectAllStates()\n }\n\n private updateOptgroupSelectAllStates(): void {\n if (!this.settings.isMultiple) {\n return\n }\n\n const selectedIds = new Set(this.store.getSelected())\n const optgroups = this.content.list.querySelectorAll(\n '.' + this.classes.getFirst('optgroup')\n )\n\n for (const optgroupEl of optgroups) {\n const selectAll = optgroupEl.querySelector(\n '.' + this.classes.getFirst('optgroupSelectAll')\n ) as HTMLDivElement | null\n\n if (!selectAll) {\n continue\n }\n\n const optionEls = optgroupEl.querySelectorAll(\n '.' + this.classes.getFirst('option')\n ) as NodeListOf<HTMLDivElement>\n\n let allSelected = optionEls.length > 0\n for (const optionEl of optionEls) {\n const id = optionEl.dataset.id\n if (!id || !selectedIds.has(id)) {\n allSelected = false\n break\n }\n }\n\n if (allSelected) {\n this.addClasses(selectAll, this.classes.selected)\n } else {\n this.removeClasses(selectAll, this.classes.selected)\n }\n\n const selectAllLabel = selectAll.querySelector('span')\n if (selectAllLabel) {\n selectAllLabel.textContent = this.optgroupSelectAllLabel(allSelected)\n }\n }\n }\n\n private optgroupSelectAllLabel(allSelected: boolean): string {\n return allSelected ? 'Unselect All' : 'Select All'\n }\n\n private isOptgroupAllSelected(\n options: Option[],\n selectedIds?: Set<string>\n ): boolean {\n if (options.length === 0) {\n return false\n }\n\n for (const option of options) {\n const isSelected = selectedIds\n ? Boolean(option.id && selectedIds.has(option.id))\n : option.selected\n\n if (!isSelected) {\n return false\n }\n }\n\n return true\n }\n\n // Create option div element\n public option(option: Option): HTMLDivElement {\n // Add hidden placeholder\n if (option.placeholder) {\n const placeholder = document.createElement('div')\n this.addClasses(placeholder, this.classes.option)\n this.addClasses(placeholder, this.classes.hide)\n return placeholder\n }\n\n // Create option\n const optionEl = document.createElement('div')\n optionEl.dataset.id = option.id // Dataset id for identifying an option\n optionEl.id = this.settings.id + '-' + option.id // Unique ID for ARIA references\n this.addClasses(optionEl, this.classes.option)\n optionEl.setAttribute('role', 'option') // WCAG attribute\n if (option.class) {\n option.class.split(' ').forEach((dataClass: string) => {\n optionEl.classList.add(dataClass)\n })\n }\n if (option.style) {\n optionEl.style.cssText = option.style\n }\n\n // Set option content\n this.setOptionElementContent(\n optionEl,\n option,\n this.content.search.input.value\n )\n\n // If option is disabled\n if (!option.display) {\n this.addClasses(optionEl, this.classes.hide)\n }\n\n // If allowed to deselect, null onclick and add disabled\n if (option.disabled) {\n this.addClasses(optionEl, this.classes.disabled)\n }\n\n // If option is selected and hideSelectedOption is true, hide it\n if (option.selected && this.settings.hideSelected) {\n this.addClasses(optionEl, this.classes.hide)\n }\n\n // If option is selected\n if (option.selected) {\n this.addClasses(optionEl, this.classes.selected)\n optionEl.setAttribute('aria-selected', 'true')\n this.main.main.setAttribute('aria-activedescendant', optionEl.id)\n } else {\n this.removeClasses(optionEl, this.classes.selected)\n optionEl.setAttribute('aria-selected', 'false')\n }\n\n // Add click event listener\n optionEl.addEventListener('click', (e: MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Setup variables\n const selectedOptions = this.store.getSelected()\n const element = e.currentTarget as HTMLDivElement\n const elementID = String(element.dataset.id)\n const storeOption = this.store.getOptionByID(elementID) ?? option\n const isCurrentlySelected = selectedOptions.includes(elementID)\n const isCmd = e.ctrlKey || e.metaKey // Cmd (Mac) or Ctrl (Windows/Linux)\n\n // If the option is disabled, do nothing\n if (option.disabled) {\n return\n }\n\n // allowDeselect only applies to single-select mode\n // In multi-select, you can always toggle options on/off\n if (\n !this.settings.isMultiple &&\n isCurrentlySelected &&\n !this.settings.allowDeselect\n ) {\n this.closeOnSingleSelectReclick(storeOption)\n return\n }\n\n // Prevent deselection of mandatory options\n if (isCurrentlySelected && storeOption.mandatory) {\n this.closeOnSingleSelectReclick(storeOption)\n return\n }\n\n // Check limit and do nothing if limit is reached and the option is not selected\n // Also check reverse for min limit and is selected (allow Cmd to bypass minSelected)\n if (\n (this.settings.isMultiple &&\n this.settings.maxSelected <= selectedOptions.length &&\n !isCurrentlySelected) ||\n (this.settings.isMultiple &&\n this.settings.minSelected >= selectedOptions.length &&\n isCurrentlySelected &&\n !isCmd)\n ) {\n return\n }\n\n // Setup variables\n let shouldUpdate = false\n const before = this.store.getSelectedOptions()\n let after = [] as Option[]\n\n // If multiple - mimic native browser multi-select behavior\n if (this.settings.isMultiple) {\n const isCurrentlySelected = before.some(\n (o: Option) => o.id === elementID\n )\n const isShift = e.shiftKey\n\n // Shift+Click: Select range from last clicked to current\n if (isShift && this.lastSelectedOption) {\n const options = this.lastRenderedOptions\n const lastIndex = options.findIndex(\n (o: Option) => o.id === this.lastSelectedOption!.id\n )\n const currentIndex = options.findIndex(\n (o: Option) => o.id === option.id\n )\n\n if (lastIndex >= 0 && currentIndex >= 0) {\n const startIndex = Math.min(lastIndex, currentIndex)\n const endIndex = Math.max(lastIndex, currentIndex)\n const rangeOptions = options.slice(startIndex, endIndex + 1)\n\n // Check if range would exceed maxSelected\n const newSelections = rangeOptions.filter(\n (opt) => !before.find((b) => b.id === opt.id)\n )\n if (\n before.length + newSelections.length <=\n this.settings.maxSelected\n ) {\n // Add range to existing selections\n after = before.concat(newSelections)\n } else {\n // Range too large, keep existing selections\n after = before\n }\n } else {\n after = before\n }\n }\n // Cmd/Ctrl+Click: Toggle selection without affecting others (keeps dropdown open)\n else if (isCmd) {\n if (isCurrentlySelected) {\n // Deselect this option\n after = before.filter((o: Option) => o.id !== elementID)\n } else {\n // Add this option to selection\n after = before.concat(storeOption)\n }\n this.lastSelectedOption = storeOption\n }\n // Regular Click: Toggle this option (add/remove), will close dropdown\n else {\n if (isCurrentlySelected) {\n // Deselect this option\n after = before.filter((o: Option) => o.id !== elementID)\n } else {\n // Add this option to selection\n after = before.concat(storeOption)\n }\n this.lastSelectedOption = storeOption\n }\n }\n\n // If single\n if (!this.settings.isMultiple) {\n if (isCurrentlySelected) {\n // If selected after would remove\n after = []\n } else {\n // If not selected after would add\n after = [storeOption]\n }\n }\n\n // If no beforeOnChange is set automatically update at end\n if (!this.callbacks.beforeChange) {\n shouldUpdate = true\n }\n\n if (this.callbacks.beforeChange) {\n // Check if beforeChange returns false\n if (this.callbacks.beforeChange(after, before) === false) {\n shouldUpdate = false\n } else {\n shouldUpdate = true\n }\n }\n\n if (shouldUpdate) {\n // Check if the option exists in the store\n // if not run addOption callback\n if (!this.store.getOptionByID(elementID)) {\n this.callbacks.addOption(option)\n }\n\n // Get values from after and set as selected\n this.callbacks.setSelected(\n after.map((o: Option) => o.id),\n false\n )\n\n // Close dropdown unless using modifier keys in multi-select\n // (mimics native multi-select behavior where you can keep selecting)\n const isModifierKey = e.ctrlKey || e.metaKey || e.shiftKey // Cmd/Ctrl or Shift\n const shouldClose =\n this.settings.closeOnSelect &&\n !(this.settings.isMultiple && isModifierKey)\n\n if (shouldClose) {\n this.requestClose('select', {\n option: storeOption,\n selectionChanged: this.selectionChanged(before, after)\n })\n }\n\n // callback that the value has changed\n if (this.callbacks.afterChange) {\n this.callbacks.afterChange(after)\n }\n }\n })\n\n return optionEl\n }\n\n public destroy(): void {\n this.stopPositionTracking()\n\n if (this.modalElements) {\n this.unlockBodyScroll()\n if (this.content.main.parentElement === this.modalElements.dialog) {\n this.restoreContentOffscreen()\n }\n this.modalElements.overlay.remove()\n this.modalElements = null\n } else if (this.bodyScrollLocked) {\n this.unlockBodyScroll()\n }\n\n // Remove main\n this.main.main.remove()\n\n // Remove content\n this.content.main.remove()\n\n this.removeDetachedInstanceDom()\n }\n\n /** Remove any leftover main/content/modal nodes for this instance (e.g. on body). */\n private removeDetachedInstanceDom(): void {\n const id = this.settings.id\n const mainClass = this.classes.getFirst('main')\n const contentClass = this.classes.getFirst('content')\n const modalClass = this.classes.getFirst('modalOverlay')\n\n document.querySelectorAll<HTMLElement>(`[data-id=\"${id}\"]`).forEach((el) => {\n if (\n el.classList.contains(mainClass) ||\n el.classList.contains(contentClass) ||\n el.classList.contains(modalClass)\n ) {\n el.remove()\n }\n })\n }\n\n private highlightText(str: string, search: any, className: string) {\n const searchTerm = search.trim()\n if (searchTerm === '') {\n return str\n }\n\n // Escape special regex characters in the search term to prevent regex injection\n const escapedSearch = searchTerm.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\n // Create a temporary div to parse HTML and work with text nodes only\n const tempDiv = document.createElement('div')\n tempDiv.innerHTML = str\n\n // Function to recursively process text nodes\n const highlightTextNodes = (node: Node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent || ''\n const regex = new RegExp('(' + escapedSearch + ')', 'i')\n\n if (regex.test(text)) {\n // Create a temporary container for the highlighted content\n const wrapper = document.createElement('span')\n const parts = text.split(regex)\n\n parts.forEach((part, index) => {\n if (part && regex.test(part)) {\n // This is the matched part - wrap it in mark\n const mark = document.createElement('mark')\n mark.className = className\n mark.textContent = part\n wrapper.appendChild(mark)\n } else if (part) {\n // This is not the matched part - keep as text\n wrapper.appendChild(document.createTextNode(part))\n }\n })\n\n // Replace the text node with the wrapper\n node.parentNode?.replaceChild(wrapper, node)\n }\n } else if (node.nodeType === Node.ELEMENT_NODE) {\n // Recursively process child nodes\n Array.from(node.childNodes).forEach((child) =>\n highlightTextNodes(child)\n )\n }\n }\n\n // Process all text nodes in the temporary div\n Array.from(tempDiv.childNodes).forEach((node) => highlightTextNodes(node))\n\n return tempDiv.innerHTML\n }\n\n private setContentDirection(direction: 'above' | 'below'): void {\n const isAbove = direction === 'above'\n const addClass = isAbove ? this.classes.dirAbove : this.classes.dirBelow\n const removeClass = isAbove ? this.classes.dirBelow : this.classes.dirAbove\n\n this.removeClasses(this.main.main, removeClass)\n this.addClasses(this.main.main, addClass)\n this.removeClasses(this.content.main, removeClass)\n this.addClasses(this.content.main, addClass)\n\n if (isAbove) {\n const mainHeight = this.main.main.offsetHeight\n const contentHeight = this.content.main.offsetHeight\n this.content.main.style.margin =\n '-' + (mainHeight + contentHeight - 1) + 'px 0px 0px 0px'\n } else {\n this.content.main.style.margin = '-1px 0px 0px 0px'\n }\n }\n\n private setContentPosition(): void {\n const containerRect = this.main.main.getBoundingClientRect()\n\n if (this.settings.contentPosition === 'relative') {\n this.applyContentWidth(containerRect)\n return\n }\n\n this.cancelOverflowShift()\n\n let top: number\n let left: number\n\n if (this.settings.contentPosition === 'fixed') {\n top = containerRect.top + containerRect.height\n left = containerRect.left\n } else {\n top = containerRect.top + window.scrollY + containerRect.height\n left = containerRect.left + window.scrollX\n }\n\n this.content.main.style.top = top + 'px'\n this.content.main.style.left = left + 'px'\n\n this.applyContentWidth(containerRect)\n\n const knownWidth = this.getKnownContentWidth(containerRect)\n if (knownWidth !== null) {\n this.content.main.style.left =\n this.adjustLeftForOverflow(left, containerRect.left, knownWidth) + 'px'\n return\n }\n\n // min/max/auto width needs one layout pass before measuring\n this.overflowShiftRaf = requestAnimationFrame(() => {\n this.overflowShiftRaf = 0\n this.applyOverflowShiftFromMeasure()\n })\n }\n\n private applyContentWidth(containerRect: DOMRect): void {\n const cw = this.settings.contentWidth\n this.content.main.style.width = ''\n this.content.main.style.minWidth = ''\n this.content.main.style.maxWidth = ''\n\n if (!cw) {\n if (this.settings.contentPosition !== 'relative') {\n this.content.main.style.width = containerRect.width + 'px'\n }\n return\n }\n\n if (cw.startsWith('>')) {\n this.content.main.style.minWidth = cw.slice(1)\n } else if (cw.startsWith('<')) {\n this.content.main.style.maxWidth = cw.slice(1)\n } else {\n this.content.main.style.width = cw\n }\n }\n\n private cancelOverflowShift(): void {\n if (this.overflowShiftRaf) {\n cancelAnimationFrame(this.overflowShiftRaf)\n this.overflowShiftRaf = 0\n }\n }\n\n /** Width in px when known before layout; null when width must be measured. */\n private getKnownContentWidth(containerRect: DOMRect): number | null {\n const cw = this.settings.contentWidth\n if (!cw) {\n return containerRect.width\n }\n if (cw.startsWith('>') || cw.startsWith('<') || cw.includes('%')) {\n return null\n }\n\n const px = parseFloat(cw)\n return Number.isNaN(px) ? null : px\n }\n\n private adjustLeftForOverflow(\n docLeft: number,\n viewportLeft: number,\n width: number\n ): number {\n const padding = 20\n const contentRight = viewportLeft + width\n if (contentRight <= window.innerWidth) {\n return docLeft\n }\n\n const overflow = contentRight - (window.innerWidth - padding)\n const newLeft = docLeft - overflow\n\n if (this.settings.contentPosition === 'fixed') {\n return Math.max(0, newLeft)\n }\n return Math.max(window.scrollX, newLeft)\n }\n\n private applyOverflowShiftFromMeasure(): void {\n const contentRect = this.content.main.getBoundingClientRect()\n const contentRight = contentRect.right\n if (contentRight <= window.innerWidth) {\n return\n }\n\n const padding = 20\n const overflow = contentRight - (window.innerWidth - padding)\n const currentLeft = parseFloat(this.content.main.style.left) || 0\n const newLeft = currentLeft - overflow\n\n if (this.settings.contentPosition === 'fixed') {\n this.content.main.style.left = Math.max(0, newLeft) + 'px'\n } else {\n this.content.main.style.left = Math.max(window.scrollX, newLeft) + 'px'\n }\n }\n\n public moveContentAbove(): void {\n this.setContentDirection('above')\n this.setContentPosition()\n }\n\n public moveContentBelow(): void {\n this.setContentDirection('below')\n this.setContentPosition()\n }\n\n public ensureElementInView(\n container: HTMLElement,\n element: HTMLElement\n ): void {\n const cTop = container.scrollTop + container.offsetTop\n const cBottom = cTop + container.clientHeight\n const eTop = element.offsetTop\n const eBottom = eTop + element.clientHeight\n\n if (eTop < cTop) {\n container.scrollTop -= cTop - eTop\n } else if (eBottom > cBottom) {\n container.scrollTop += eBottom - cBottom\n }\n }\n\n public putContent(): 'up' | 'down' {\n const mainHeight = this.main.main.offsetHeight\n const mainRect = this.main.main.getBoundingClientRect()\n const contentHeight = this.content.main.offsetHeight\n const spaceBelow = window.innerHeight - (mainRect.top + mainHeight)\n\n if (spaceBelow <= contentHeight) {\n if (mainRect.top > contentHeight) {\n return 'up'\n }\n return 'down'\n }\n\n return 'down'\n }\n\n // Updates deselect based on item count and allowDeselect setting\n public updateDeselectAll(): void {\n if (!this.store || !this.settings) {\n return\n }\n const selected = this.store.getSelectedOptions()\n const hasSelectedItems = selected && selected.length > 0\n const isMultiple = this.settings.isMultiple\n const allowDeselect = this.settings.allowDeselect\n const atMinSelected = this.isAtMinSelected()\n\n const deselectButton = this.main.deselect.main\n const hideClass = this.classes.hide\n\n if (\n allowDeselect &&\n !(isMultiple && !hasSelectedItems) &&\n !atMinSelected\n ) {\n this.removeClasses(deselectButton, hideClass)\n } else {\n this.addClasses(deselectButton, hideClass)\n }\n }\n}\n","/**\n * Pure classification of MutationObserver records on the native <select>.\n *\n * Select.observeCall() uses these flags to decide which sync path to run\n * (class/disabled vs full structure vs selection-only). Keeping this logic\n * separate makes it testable without spinning up a full SlimSelect instance.\n */\n\n/** What changed in a single observer callback batch (flags can all be true). */\nexport interface MutationFlags {\n /** Native select class attribute changed — sync to render styles only. */\n classChanged: boolean\n /** Native select disabled attribute changed — enable/disable SlimSelect. */\n disabledChanged: boolean\n /**\n * Options or optgroups were added, removed, or had attributes edited.\n * Triggers a full structure sync (store + native DOM + render).\n */\n optgroupOptionChanged: boolean\n /**\n * Selection may have changed without a separate `change` event yet.\n * Used when a newly added <option> is already the select's value.\n */\n selectionChanged: boolean\n}\n\n/**\n * Scan a MutationObserver batch and return which kinds of updates are needed.\n *\n * The observer watches the <select> with subtree: true, so mutations can\n * target the select itself or any child <option> / <optgroup>.\n */\nexport function classifyMutations(\n mutations: MutationRecord[],\n select: HTMLSelectElement\n): MutationFlags {\n const flags: MutationFlags = {\n classChanged: false,\n disabledChanged: false,\n optgroupOptionChanged: false,\n selectionChanged: false\n }\n\n for (const m of mutations) {\n // Mutations directly on the <select> element\n if (m.target === select) {\n if (m.attributeName === 'disabled') {\n flags.disabledChanged = true\n }\n\n if (m.attributeName === 'class') {\n flags.classChanged = true\n }\n\n if (m.type === 'childList') {\n // Detect \"add option and it becomes selected\" in one DOM update\n // (e.g. appendChild + select.value = 'x'). Without this, we'd only\n // run structure sync and miss that selection also changed.\n for (const n of Array.from(m.addedNodes)) {\n if (\n n.nodeName === 'OPTION' &&\n (n as HTMLOptionElement).value === select.value\n ) {\n flags.selectionChanged = true\n break\n }\n }\n\n // Any childList on the select means options were added/removed/replaced\n flags.optgroupOptionChanged = true\n }\n }\n\n // Attribute edits on options (selected, text, data-*) or optgroup changes\n // bubble up as mutations on child nodes, not on the select itself\n if (m.target.nodeName === 'OPTGROUP' || m.target.nodeName === 'OPTION') {\n flags.optgroupOptionChanged = true\n }\n }\n\n return flags\n}\n","import {\n copyOptionData,\n kebabCase,\n hasClassInTree,\n selectedIdsEqual\n} from './helpers'\nimport { classifyMutations } from './mutations'\nimport { Optgroup, Option } from './store'\n\nexport default class Select {\n public select: HTMLSelectElement\n\n // Mutation observer fields\n public onValueChange?: (value: Option[]) => void\n public onClassChange?: (classes: string[]) => void\n public onDisabledChange?: (disabled: boolean) => void\n public onOptionsChange?: (data: (Option | Optgroup)[]) => void\n public onLabelClick?: () => void\n\n // Change observers\n private listen: boolean = false\n private observer: MutationObserver | null = null\n private isUpdating: boolean = false\n private pendingOptionsChange: (Option | Optgroup)[] | null = null\n\n // Event handlers for preventing native select behavior (especially on iOS Safari)\n private preventNativeSelect: ((e: Event) => void) | null = null\n private preventNativeSelectMousedown: ((e: Event) => void) | null = null\n private preventNativeSelectFocus: ((e: Event) => void) | null = null\n private restoreAriaHiddenOnBlur: ((e: Event) => void) | null = null\n\n constructor(select: HTMLSelectElement) {\n this.select = select\n\n this.valueChange = this.valueChange.bind(this)\n // Add change event listener\n this.select.addEventListener('change', this.valueChange, {\n // allow bubbling of event\n passive: true\n })\n\n // Initiate mutation observer\n this.observer = new MutationObserver(this.observeCall.bind(this))\n\n // Start listening for changes\n this.changeListen(true)\n }\n\n public enable(): void {\n this.select.disabled = false\n }\n\n public disable(): void {\n this.select.disabled = true\n }\n\n public hideUI(): void {\n this.select.tabIndex = -1\n // Visually hide but keep focusable for form validation\n // Use 1px dimensions so browser validation popup can display\n this.select.style.position = 'absolute'\n this.select.style.width = '1px'\n this.select.style.height = '1px'\n this.select.style.opacity = '0'\n this.select.style.overflow = 'hidden'\n this.select.style.pointerEvents = 'none'\n // Remove any spacing or borders that could affect layout\n this.select.style.margin = '0'\n this.select.style.padding = '0'\n this.select.style.borderWidth = '0'\n // Clip to completely hide the 1px\n this.select.style.clipPath = 'inset(50%)'\n // Only apply aria-hidden if the select doesn't currently hold focus.\n // Browsers (Chrome) block aria-hidden on a focused element and log a\n // warning, since focus must not be hidden from assistive technology.\n // If the select is focused right now, the blur handler below will\n // apply aria-hidden once focus leaves the element.\n if (document.activeElement !== this.select) {\n this.select.setAttribute('aria-hidden', 'true')\n }\n\n // Prevent native select from opening when label is clicked (especially on iOS Safari)\n // iOS Safari programmatically focuses/clicks the select when label is clicked,\n // bypassing pointer-events: none, so we need to prevent these events\n // Only add listeners if they haven't been added yet\n if (!this.preventNativeSelect) {\n this.preventNativeSelect = (e: Event) => {\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n }\n\n this.preventNativeSelectMousedown = (e: Event) => {\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n }\n\n this.preventNativeSelectFocus = (e: Event) => {\n // Focus events are not cancelable, so the select may still end up\n // focused (e.g. the browser focusing an invalid control during form\n // validation, or a programmatic select.focus() call). Lift aria-hidden\n // while the element holds focus so assistive technology isn't blocked\n // from it; it gets restored by the blur handler.\n this.select.removeAttribute('aria-hidden')\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n }\n\n // Re-apply aria-hidden once focus leaves the hidden select\n this.restoreAriaHiddenOnBlur = () => {\n this.select.setAttribute('aria-hidden', 'true')\n }\n\n // Add event listeners with capture phase to catch events before they reach the select\n this.select.addEventListener('click', this.preventNativeSelect, {\n capture: true,\n passive: false\n })\n this.select.addEventListener(\n 'mousedown',\n this.preventNativeSelectMousedown,\n { capture: true, passive: false }\n )\n this.select.addEventListener('focus', this.preventNativeSelectFocus, {\n capture: true,\n passive: false\n })\n this.select.addEventListener('blur', this.restoreAriaHiddenOnBlur, {\n capture: true,\n passive: true\n })\n }\n }\n\n public showUI(): void {\n this.select.removeAttribute('tabindex')\n // Reset visual hiding styles\n this.select.style.position = ''\n this.select.style.width = ''\n this.select.style.height = ''\n this.select.style.opacity = ''\n this.select.style.overflow = ''\n this.select.style.pointerEvents = ''\n this.select.style.margin = ''\n this.select.style.padding = ''\n this.select.style.borderWidth = ''\n this.select.style.clipPath = ''\n this.select.removeAttribute('aria-hidden')\n\n // Remove event listeners that prevent native select behavior\n if (this.preventNativeSelect) {\n this.select.removeEventListener('click', this.preventNativeSelect, {\n capture: true\n })\n this.preventNativeSelect = null\n }\n if (this.preventNativeSelectMousedown) {\n this.select.removeEventListener(\n 'mousedown',\n this.preventNativeSelectMousedown,\n { capture: true }\n )\n this.preventNativeSelectMousedown = null\n }\n if (this.preventNativeSelectFocus) {\n this.select.removeEventListener('focus', this.preventNativeSelectFocus, {\n capture: true\n })\n this.preventNativeSelectFocus = null\n }\n if (this.restoreAriaHiddenOnBlur) {\n this.select.removeEventListener('blur', this.restoreAriaHiddenOnBlur, {\n capture: true\n })\n this.restoreAriaHiddenOnBlur = null\n }\n }\n\n public changeListen(listen: boolean) {\n this.listen = listen\n\n // Start listening for changes\n if (listen) {\n if (this.observer) {\n this.observer.observe(this.select, {\n subtree: true, // subtree for optgroups options\n childList: true, // children changes\n attributes: true // attributes changes\n })\n }\n }\n\n // Stop listening for changes\n if (!listen) {\n if (this.observer) {\n this.observer.disconnect()\n }\n }\n }\n\n // This function get triggers when the select value changes\n // and will call the onValueChange function if it exists\n public valueChange(ev: Event): boolean {\n if (this.listen && this.onValueChange) {\n this.onValueChange(this.getSelectedOptions())\n }\n\n // Allow bubbling back to other change event listeners\n return true\n }\n\n private observeCall(mutations: MutationRecord[]): void {\n // If we are not listening, do nothing.\n if (!this.listen) {\n return\n }\n\n // Pure classifier — separates class/disabled/structure/selection mutations\n const {\n classChanged,\n disabledChanged,\n optgroupOptionChanged,\n selectionChanged: initialSelectionChanged\n } = classifyMutations(mutations, this.select)\n let selectionChanged = initialSelectionChanged\n\n // If class has changed then call the class change function\n if (classChanged && this.onClassChange) {\n this.onClassChange(this.select.className.split(' '))\n }\n\n // If disabled has changed then call the disabled change function\n if (disabledChanged && this.onDisabledChange) {\n this.changeListen(false)\n this.onDisabledChange(this.select.disabled)\n this.changeListen(true)\n }\n\n // If optgroup or option has changed then call the select change function\n if (optgroupOptionChanged && this.onOptionsChange) {\n // If we're currently updating, queue this change to process after update completes\n if (this.isUpdating) {\n // Only queue if the select element actually has options (not empty from updateOptions clearing)\n // Check the select element directly, not getData() which might return stale data\n if (this.select.options.length > 0) {\n const currentData = this.getData()\n // Only queue if we have actual data\n if (currentData.length > 0) {\n this.pendingOptionsChange = currentData\n }\n }\n if (selectionChanged) {\n this.select.dispatchEvent(new Event('change'))\n }\n return\n }\n\n this.changeListen(false)\n this.onOptionsChange(this.getData())\n this.changeListen(true)\n\n // Structure sync includes selection from getData(); skip redundant change event\n selectionChanged = false\n }\n\n if (selectionChanged) {\n this.select.dispatchEvent(new Event('change'))\n }\n }\n\n // From the select element pull optgroup and options into data\n public getData(): (Option | Optgroup)[] {\n let data = []\n\n // Loop through nodes and get data\n const nodes = this.select.childNodes as any as\n | HTMLOptGroupElement[]\n | HTMLOptionElement[]\n for (const n of nodes) {\n // Optgroup\n if (n.nodeName === 'OPTGROUP') {\n data.push(this.getDataFromOptgroup(n as HTMLOptGroupElement))\n }\n\n // Option\n if (n.nodeName === 'OPTION') {\n data.push(this.getDataFromOption(n as HTMLOptionElement))\n }\n }\n\n return data\n }\n\n public getDataFromOptgroup(optgroup: HTMLOptGroupElement): Optgroup {\n let data = {\n id: optgroup.id,\n label: optgroup.label,\n selectAll: optgroup.dataset\n ? optgroup.dataset.selectall === 'true'\n : false,\n closable: optgroup.dataset ? optgroup.dataset.closable : 'off',\n options: []\n } as Optgroup\n\n const options = optgroup.childNodes as any as HTMLOptionElement[]\n for (const o of options) {\n if (o.nodeName === 'OPTION') {\n data.options!.push(this.getDataFromOption(o as HTMLOptionElement))\n }\n }\n\n return data\n }\n\n // From passed in option pull pieces of usable information\n public getDataFromOption(option: HTMLOptionElement): Option {\n return {\n id: option.id,\n value: option.value,\n text: option.text,\n html: option.dataset && option.dataset.html ? option.dataset.html : '',\n defaultSelected: option.defaultSelected,\n selected: option.selected,\n display: option.style.display !== 'none',\n disabled: option.disabled,\n mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,\n placeholder: option.dataset.placeholder === 'true',\n class: option.className,\n style: option.style.cssText,\n data: copyOptionData(option.dataset)\n } as Option\n }\n\n public getSelectedOptions(): Option[] {\n let options = []\n\n // Loop through options and set selected\n const opts = this.select.childNodes as any as (\n | HTMLOptGroupElement\n | HTMLOptionElement\n )[]\n for (const o of opts) {\n if (o.nodeName === 'OPTGROUP') {\n const optgroupOptions = o.childNodes as any as HTMLOptionElement[]\n for (const oo of optgroupOptions) {\n if (oo.nodeName === 'OPTION') {\n const option = oo as HTMLOptionElement\n if (option.selected) {\n options.push(this.getDataFromOption(option))\n }\n }\n }\n }\n\n if (o.nodeName === 'OPTION') {\n const option = o as HTMLOptionElement\n if (option.selected) {\n options.push(this.getDataFromOption(option))\n }\n }\n }\n\n return options\n }\n\n public getSelectedValues(): string[] {\n return this.getSelectedOptions().map((option) => option.value)\n }\n\n /** True when every value has a matching native <option> (empty list is vacuously true). */\n public hasOptionValues(values: string[]): boolean {\n if (values.length === 0) {\n return true\n }\n\n const nativeValues = new Set(\n Array.from(this.select.options).map((option) => option.value)\n )\n return values.every((value) => nativeValues.has(value))\n }\n\n public setSelected(ids: string[]): void {\n // Stop listening to changes\n this.changeListen(false)\n\n // Loop through options and set selected\n const options = this.select.childNodes as any as (\n | HTMLOptGroupElement\n | HTMLOptionElement\n )[]\n for (const o of options) {\n if (o.nodeName === 'OPTGROUP') {\n const optgroup = o as HTMLOptGroupElement\n const optgroupOptions =\n optgroup.childNodes as any as HTMLOptionElement[]\n for (const oo of optgroupOptions) {\n if (oo.nodeName === 'OPTION') {\n const option = oo as HTMLOptionElement\n option.selected = ids.includes(option.id)\n }\n }\n }\n\n if (o.nodeName === 'OPTION') {\n const option = o as HTMLOptionElement\n option.selected = ids.includes(option.id)\n }\n }\n\n // Keep native value in sync for form validation and parent bindings\n const selected = this.getSelectedOptions()\n if (!this.select.multiple) {\n this.select.value = selected.length === 1 ? selected[0].value : ''\n }\n\n // Fire native change listeners while observer is paused to avoid re-entrant sync\n this.select.dispatchEvent(new Event('change', { bubbles: true }))\n\n this.changeListen(true)\n }\n\n // Set selected options by value instead of id.\n // SyncCoordinator uses this path — HTML option ids are often empty.\n // This is useful when the id is not known\n // and only the value is known\n // but the value is not unique and can be duplicated\n public setSelectedByValue(values: string[]): void {\n // Stop listening to changes\n this.changeListen(false)\n\n // Loop through options and set selected\n const options = this.select.childNodes as any as (\n | HTMLOptGroupElement\n | HTMLOptionElement\n )[]\n for (const o of options) {\n if (o.nodeName === 'OPTGROUP') {\n const optgroup = o as HTMLOptGroupElement\n const optgroupOptions =\n optgroup.childNodes as any as HTMLOptionElement[]\n for (const oo of optgroupOptions) {\n if (oo.nodeName === 'OPTION') {\n const option = oo as HTMLOptionElement\n option.selected = values.includes(option.value)\n }\n }\n }\n\n if (o.nodeName === 'OPTION') {\n const option = o as HTMLOptionElement\n option.selected = values.includes(option.value)\n }\n }\n\n const selected = this.getSelectedOptions()\n if (!this.select.multiple) {\n // Sync native value for form validation / Vue v-model\n this.select.value = selected.length === 1 ? selected[0].value : ''\n }\n\n // Fire native change listeners while observer is paused to avoid re-entrant sync\n this.select.dispatchEvent(new Event('change', { bubbles: true }))\n\n this.changeListen(true)\n }\n\n public updateSelect(id?: string, style?: string, classes?: string[]): void {\n // Stop listening to changes\n this.changeListen(false)\n\n // Update id, only if the id isnt already set\n if (id) {\n this.select.dataset.id = id\n }\n\n // Update style\n if (style) {\n this.select.style.cssText = style\n }\n\n // Update classes\n if (classes) {\n this.select.className = ''\n classes.forEach((c) => {\n if (c.trim() !== '') {\n this.select.classList.add(c.trim())\n }\n })\n }\n\n // Start listening to changes\n this.changeListen(true)\n }\n\n public updateOptions(data: (Option | Optgroup)[]): void {\n // Don't update if data is empty (prevents clearing select when no data)\n if (!data || data.length === 0) {\n return\n }\n\n // Set updating flag FIRST to prevent mutation observer from processing during update\n // This must be set before stopping listening so any queued mutations see the flag\n this.isUpdating = true\n this.pendingOptionsChange = null\n\n // Stop listening to changes\n this.changeListen(false)\n\n // Option-list rebuilds (e.g. API search) must not fire change unless selection changes\n const selectedBefore = this.getSelectedValues()\n\n // Clear out select\n this.select.innerHTML = ''\n\n for (const d of data) {\n if (d instanceof Optgroup) {\n this.select.appendChild(this.createOptgroup(d))\n }\n\n if (d instanceof Option) {\n this.select.appendChild(this.createOption(d))\n }\n }\n\n // Only fire native change when the selected value(s) actually changed (#696)\n if (!selectedIdsEqual(selectedBefore, this.getSelectedValues())) {\n this.select.dispatchEvent(new Event('change', { bubbles: true }))\n }\n\n // Start listening to changes\n this.changeListen(true)\n\n // Clear updating flag\n this.isUpdating = false\n\n // Process any pending options change that was queued during the update\n // Only process if it has data (don't process empty data from innerHTML clearing)\n if (this.pendingOptionsChange !== null) {\n const pending: (Option | Optgroup)[] = this.pendingOptionsChange\n if (pending.length > 0 && this.onOptionsChange) {\n this.pendingOptionsChange = null\n // Process the queued change\n this.changeListen(false)\n this.onOptionsChange(pending)\n this.changeListen(true)\n } else {\n // Clear pending if it was empty\n this.pendingOptionsChange = null\n }\n }\n }\n\n public createOptgroup(optgroup: Optgroup): HTMLOptGroupElement {\n const optgroupEl = document.createElement('optgroup')\n optgroupEl.id = optgroup.id\n optgroupEl.label = optgroup.label\n if (optgroup.selectAll) {\n optgroupEl.dataset.selectAll = 'true'\n }\n if (optgroup.closable !== 'off') {\n optgroupEl.dataset.closable = optgroup.closable\n }\n if (optgroup.options) {\n for (const option of optgroup.options) {\n optgroupEl.appendChild(this.createOption(option as Option))\n }\n }\n return optgroupEl\n }\n\n public createOption(info: Option): HTMLOptionElement {\n const optionEl = document.createElement('option')\n optionEl.id = info.id\n optionEl.value = info.value\n optionEl.textContent = info.text\n if (info.html !== '') {\n optionEl.setAttribute('data-html', info.html)\n }\n optionEl.defaultSelected = info.defaultSelected\n optionEl.selected = info.selected // Explicitly set selected because defaultSelected: true sets selected to true\n if (info.disabled) {\n optionEl.disabled = true\n }\n if (!info.display) {\n optionEl.style.display = 'none'\n }\n if (info.placeholder) {\n optionEl.setAttribute('data-placeholder', 'true')\n }\n if (info.mandatory) {\n optionEl.setAttribute('data-mandatory', 'true')\n }\n if (info.class) {\n info.class.split(' ').forEach((optionClass: string) => {\n optionEl.classList.add(optionClass)\n })\n }\n if (info.data && typeof info.data === 'object') {\n Object.keys(info.data).forEach((key) => {\n optionEl.setAttribute('data-' + kebabCase(key), info.data[key])\n })\n }\n\n return optionEl\n }\n\n // Find and handle labels associated with this select\n public setupLabelHandlers(): void {\n const labels: HTMLLabelElement[] = []\n\n // Find labels that point to this select via 'for' attribute\n const selectId = this.select.id\n if (selectId) {\n const labelsByFor = document.querySelectorAll<HTMLLabelElement>(\n `label[for=\"${selectId}\"]`\n )\n labelsByFor.forEach((label) => labels.push(label))\n }\n\n // Find labels that wrap this select (label contains select)\n let parent = this.select.parentElement\n while (parent && parent !== document.body) {\n if (parent.tagName === 'LABEL') {\n labels.push(parent as HTMLLabelElement)\n break\n }\n parent = parent.parentElement\n }\n\n // Remove duplicates\n const uniqueLabels = Array.from(new Set(labels))\n\n uniqueLabels.forEach((label) => {\n // Skip if already handled\n if ((label as any).__slimSelectLabelHandler) {\n return\n }\n\n // Add click handler to label\n const labelClickHandler = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n\n // Check if click is on SlimSelect UI elements (main div or content)\n const isSlimSelectElement = hasClassInTree(\n target,\n this.select.dataset.id!\n )\n\n // Prevent default label behavior (focusing the select)\n // This needs to happen for all clicks on the label or its children\n // to prevent the browser from focusing the hidden select\n e.preventDefault()\n // e.stopPropagation() // dont stop propagation\n\n // Only trigger the toggle if the click is NOT on SlimSelect elements\n // This allows clicking label text/children to toggle, while wrapped SlimSelect handles its own clicks\n if (!isSlimSelectElement && this.onLabelClick) {\n this.onLabelClick()\n }\n }\n\n // Store the handler on the label for cleanup later\n ;(label as any).__slimSelectLabelHandler = labelClickHandler\n label.addEventListener('click', labelClickHandler, {\n capture: true,\n passive: false\n })\n })\n }\n\n // Remove label handlers\n public removeLabelHandlers(): void {\n const labels: HTMLLabelElement[] = []\n\n // Find labels that point to this select via 'for' attribute\n const selectId = this.select.id\n if (selectId) {\n const labelsByFor = document.querySelectorAll<HTMLLabelElement>(\n `label[for=\"${selectId}\"]`\n )\n labelsByFor.forEach((label) => labels.push(label))\n }\n\n // Find labels that wrap this select\n let parent = this.select.parentElement\n while (parent && parent !== document.body) {\n if (parent.tagName === 'LABEL') {\n labels.push(parent as HTMLLabelElement)\n break\n }\n parent = parent.parentElement\n }\n\n // Remove duplicates\n const uniqueLabels = Array.from(new Set(labels))\n\n uniqueLabels.forEach((label) => {\n const handler = (label as any).__slimSelectLabelHandler\n if (handler) {\n label.removeEventListener('click', handler, { capture: true })\n delete (label as any).__slimSelectLabelHandler\n }\n })\n }\n\n public destroy() {\n this.changeListen(false)\n\n // Remove event change listener\n this.select.removeEventListener('change', this.valueChange)\n\n // Remove event listeners that prevent native select behavior\n if (this.preventNativeSelect) {\n this.select.removeEventListener('click', this.preventNativeSelect, {\n capture: true\n })\n this.preventNativeSelect = null\n }\n if (this.preventNativeSelectMousedown) {\n this.select.removeEventListener(\n 'mousedown',\n this.preventNativeSelectMousedown,\n { capture: true }\n )\n this.preventNativeSelectMousedown = null\n }\n if (this.preventNativeSelectFocus) {\n this.select.removeEventListener('focus', this.preventNativeSelectFocus, {\n capture: true\n })\n this.preventNativeSelectFocus = null\n }\n if (this.restoreAriaHiddenOnBlur) {\n this.select.removeEventListener('blur', this.restoreAriaHiddenOnBlur, {\n capture: true\n })\n this.restoreAriaHiddenOnBlur = null\n }\n\n // Disconnect observer and null\n if (this.observer) {\n this.observer.disconnect()\n this.observer = null\n }\n\n // Remove label handlers\n this.removeLabelHandlers()\n\n // Remove dataset id from original select\n delete this.select.dataset.id\n\n // Show the original select\n this.showUI()\n }\n}\n","/**\n * Central sync pipeline for SlimSelect.\n *\n * All paths that change store, native <select>, or custom UI should go through\n * SyncCoordinator instead of calling setData/setSelected directly. This gives us:\n * - One place to batch/coalesce updates\n * - Lightweight selection sync (no full native DOM rebuild)\n * - No-op skips when nothing actually changed\n *\n * Wired from SlimSelect: native observer → enqueue(native), public API → enqueue(api),\n * render callbacks → enqueue(ui).\n */\n\nimport Render from './render'\nimport Select from './select'\nimport Store, { Optgroup, Option } from './store'\nimport { dataStructureEqual, selectedIdsEqual } from './helpers'\n\n/** Where a change originated — affects batching and render behavior. */\nexport type ChangeSource = 'native' | 'ui' | 'api'\n\nexport interface SyncEvents {\n afterChange?: (newVal: Option[]) => void\n error?: (err: Error) => void\n}\n\n/**\n * A single unit of work in the sync queue.\n * Structure = replace option list; selection = change selected only; addOption = append one.\n */\nexport type SyncChange =\n | {\n type: 'structure'\n data: (Partial<Option> | Partial<Optgroup>)[]\n source: ChangeSource\n /** Keep current selection when replacing data (async search results). */\n preserveSelection?: boolean\n /** API search results — do not update the catalog baseline. */\n isSearchResult?: boolean\n }\n | {\n type: 'selection'\n values: string | string[]\n source: ChangeSource\n /** false when Vue/parent is pushing modelValue down (avoid emit loop). */\n runAfterChange?: boolean\n }\n | { type: 'addOption'; option: Partial<Option>; source: ChangeSource }\n\nexport interface SyncDeps {\n select: Select\n store: Store\n render: Render\n events: SyncEvents\n search?: (value: string) => void\n onError?: (err: Error) => void\n}\n\n/** Skip structure sync when incoming data matches what's already in the store. */\nexport function shouldSkipStructureUpdate(\n store: Store,\n data: (Partial<Option> | Partial<Optgroup>)[]\n): boolean {\n return dataStructureEqual(store.getData(false), data)\n}\n\n/**\n * Resolve setSelected() arguments to option ids.\n * Accepts either ids or values for backward compatibility.\n */\nexport function resolveSelectedIds(\n store: Store,\n values: string | string[]\n): string[] {\n const valueList = Array.isArray(values) ? values : [values]\n const options = store.getDataOptions(false)\n const ids: string[] = []\n\n for (const value of valueList) {\n if (options.find((option) => option.id == value)) {\n ids.push(value)\n continue\n }\n\n // Value may match multiple options (duplicate values) — select all matches\n for (const option of options.filter((option) => option.value == value)) {\n ids.push(option.id)\n }\n }\n\n return ids\n}\n\nexport default class SyncCoordinator {\n private queue: SyncChange[] = []\n private flushScheduled = false\n /** True while applyChange is running — prevents re-entrant flush loops. */\n public isSyncing = false\n\n constructor(private deps: SyncDeps) {}\n\n public enqueue(change: SyncChange): void {\n this.queue.push(change)\n\n // Native mutations often arrive in bursts from MutationObserver; coalesce\n // them in one microtask so we render once per frame.\n if (change.source === 'native') {\n if (!this.flushScheduled) {\n this.flushScheduled = true\n queueMicrotask(() => this.flush())\n }\n return\n }\n\n // API/UI (setData, setSelected, clicks) should feel instant to callers.\n // If we're already inside flush(), defer until the current batch finishes.\n if (!this.isSyncing) {\n this.flush()\n }\n }\n\n /** Process everything in the queue. Callable from tests for deterministic native sync. */\n public flush(): void {\n this.flushScheduled = false\n\n if (this.queue.length === 0) {\n return\n }\n\n const batch = this.coalesceBatch(this.queue)\n this.queue = []\n\n this.isSyncing = true\n try {\n for (const change of batch) {\n this.applyChange(change)\n }\n } finally {\n this.isSyncing = false\n // Changes enqueued during applyChange (e.g. async search) run next\n if (this.queue.length > 0) {\n this.flush()\n }\n }\n }\n\n /**\n * Collapse a batch into the minimum work needed.\n * Structure sync already includes selection from getData(), so drop redundant\n * selection changes in the same batch. When multiple structure updates arrive,\n * only the last one wins.\n */\n private coalesceBatch(changes: SyncChange[]): SyncChange[] {\n const hasStructure = changes.some((c) => c.type === 'structure')\n const hasAddOption = changes.some((c) => c.type === 'addOption')\n\n if (hasStructure || hasAddOption) {\n const structureChanges = changes.filter(\n (c) => c.type === 'structure' || c.type === 'addOption'\n )\n const lastStructure = structureChanges[structureChanges.length - 1]\n\n if (lastStructure?.type === 'structure') {\n return [lastStructure]\n }\n\n return structureChanges\n }\n\n const selectionChanges = changes.filter((c) => c.type === 'selection')\n if (selectionChanges.length > 0) {\n return [selectionChanges[selectionChanges.length - 1]]\n }\n\n return changes\n }\n\n private applyChange(change: SyncChange): void {\n switch (change.type) {\n case 'structure':\n this.applyStructure(\n change.data,\n change.source,\n change.preserveSelection,\n change.isSearchResult\n )\n break\n case 'selection':\n this.applySelection(\n change.values,\n change.source,\n change.runAfterChange !== false\n )\n break\n case 'addOption':\n this.applyAddOption(change.option)\n break\n }\n }\n\n /**\n * Full sync: store → native <select> rebuild → render values + options.\n * Used when the option list itself changes (setData, native DOM edits).\n * API search results update store + UI only — native select stays form/selection state.\n */\n private applyStructure(\n data: (Partial<Option> | Partial<Optgroup>)[],\n _source: ChangeSource,\n preserveSelection = false,\n isSearchResult = false\n ): void {\n const { store, select, render, events } = this.deps\n\n // API search always shows \"Searching...\" first — even when results match the\n // current store, we must re-render the UI so that placeholder is cleared (#695).\n // Search hits stay out of the native <select> (form options update on selection).\n if (!isSearchResult && shouldSkipStructureUpdate(store, data)) {\n return\n }\n\n const selected = store.getSelected()\n\n const err = store.validateDataArray(data)\n if (err) {\n if (events.error) {\n events.error(err)\n } else if (this.deps.onError) {\n this.deps.onError(err)\n }\n return\n }\n\n store.setData(data, preserveSelection)\n const dataClean = store.getData(false)\n\n if (!isSearchResult) {\n store.snapshotCatalog()\n }\n\n // Ephemeral API search pages must not rewrite the native <select>\n if (!isSearchResult) {\n select.updateOptions(dataClean)\n }\n\n render.renderValues()\n render.renderOptions(dataClean)\n\n if (events.afterChange && !selectedIdsEqual(selected, store.getSelected())) {\n events.afterChange(store.getSelectedOptions())\n }\n }\n\n /**\n * Sync native <select> to current selection (form truth).\n * When selected options are missing from the native DOM (e.g. picked from API\n * search results), rebuild from selected options only — never from search hits.\n */\n private syncNativeSelection(): void {\n const { store, select } = this.deps\n const selectedOptions = store.getSelectedOptions()\n const selectedValues = store.getSelectedValues()\n\n if (!select.hasOptionValues(selectedValues)) {\n if (selectedOptions.length > 0) {\n select.updateOptions(selectedOptions)\n return\n }\n\n // Empty selection with no matching native options: prefer catalog placeholder\n const placeholder = store\n .getCatalogData()\n .find(\n (item): item is Option =>\n item instanceof Option && item.placeholder === true\n )\n if (placeholder) {\n select.updateOptions([new Option({ ...placeholder, selected: true })])\n return\n }\n }\n\n // Use values on the native DOM — HTML option ids may be empty while store uses generated ids\n select.setSelectedByValue(selectedValues)\n }\n\n /**\n * Lightweight selection sync: flip option.selected on native DOM only.\n * Avoids select.updateOptions() (innerHTML rebuild) for selection-only changes\n * when the options already exist on the native select.\n */\n private applySelection(\n values: string | string[],\n _source: ChangeSource,\n runAfterChange: boolean\n ): void {\n const { store, select, render, events } = this.deps\n\n const selected = store.getSelected()\n const ids = resolveSelectedIds(store, values)\n\n if (selectedIdsEqual(selected, ids)) {\n return\n }\n\n store.setSelectedBy('id', ids)\n this.syncNativeSelection()\n render.renderValues()\n\n const searchValue = render.content.search.input.value.trim()\n if (searchValue !== '') {\n if (render.hasRenderedOptions()) {\n render.updateOptionSelection()\n } else if (this.deps.search) {\n this.deps.search(searchValue)\n }\n } else if (render.canUpdateOptionSelectionInPlace()) {\n render.updateOptionSelection()\n } else {\n render.renderOptions(store.getData(false))\n }\n\n if (\n runAfterChange &&\n events.afterChange &&\n !selectedIdsEqual(selected, store.getSelected())\n ) {\n events.afterChange(store.getSelectedOptions())\n }\n }\n\n /** Append a single option then full-sync native + render (same as legacy addOption). */\n private applyAddOption(option: Partial<Option>): void {\n const { store, select, render, events } = this.deps\n const selected = store.getSelected()\n const searchValue = render.content.search.input.value.trim()\n const isApiSearchOverlay = searchValue !== '' && !!this.deps.search\n const optionValue = option.value ?? option.text ?? ''\n\n const optionExists = (data: (Option | Optgroup)[]): boolean => {\n for (const item of data) {\n if (item instanceof Optgroup) {\n if (\n item.options.some((opt) => (opt.value ?? opt.text) === optionValue)\n ) {\n return true\n }\n continue\n }\n\n if ((item.value ?? item.text) === optionValue) {\n return true\n }\n }\n\n return false\n }\n\n if (!optionExists(store.getData(false))) {\n if (isApiSearchOverlay) {\n const baseline = store.getCatalogData()\n if (!optionExists(baseline)) {\n store.setData([...baseline, new Option(option)], true)\n }\n store.snapshotCatalog()\n } else {\n store.addOption(option)\n store.snapshotCatalog()\n }\n }\n\n const data = store.getData(false)\n\n // During API search, native select is form truth (selected options), not search hits\n if (isApiSearchOverlay) {\n const selectedOptions = store.getSelectedOptions()\n if (selectedOptions.length > 0) {\n select.updateOptions(selectedOptions)\n }\n } else {\n select.updateOptions(data)\n }\n\n render.renderValues()\n render.renderOptions(data)\n\n if (events.afterChange && !selectedIdsEqual(selected, store.getSelected())) {\n events.afterChange(store.getSelectedOptions())\n }\n }\n}\n","import CssClasses from './classes'\nimport { getAnimationTimeout } from './animations'\nimport GlobalEvents, { hasClassInTree } from './events'\nimport { debounce, getAssociatedLabelText } from './helpers'\nimport Lifecycle from './lifecycle'\nimport Render, { CloseInfo } from './render'\nimport Select from './select'\nimport Settings, { MODAL_MOBILE_BREAKPOINT } from './settings'\nimport Store, { Option, Optgroup } from './store'\nimport SyncCoordinator from './sync'\n\n// Export classes\nexport { Settings, Option, Optgroup, MODAL_MOBILE_BREAKPOINT }\nexport type { ModalSetting } from './settings'\n\n// Export interfaces from render\nexport type { Main, Content, Search, CloseInfo, CloseSource } from './render'\n\nexport interface Config {\n select: string | Element\n data?: (Partial<Option> | Partial<Optgroup>)[]\n settings?: Partial<Settings>\n cssClasses?: Partial<CssClasses>\n events?: Events\n}\n\nexport interface Events {\n search?: (\n searchValue: string,\n selected: Option[],\n catalog?: (Option | Optgroup)[]\n ) =>\n | Promise<(Partial<Option> | Partial<Optgroup>)[]>\n | (Partial<Option> | Partial<Optgroup>)[]\n searchFilter?: (option: Option, search: string) => boolean\n addable?: (\n value: string\n ) =>\n | Promise<Partial<Option> | string>\n | Partial<Option>\n | string\n | false\n | null\n | undefined\n | Error\n beforeChange?: (newVal: Option[], oldVal: Option[]) => boolean | void\n afterChange?: (newVal: Option[]) => void\n beforeOpen?: () => void\n afterOpen?: () => void\n beforeClose?: (info: CloseInfo) => boolean | void\n afterClose?: () => void\n error?: (err: Error) => void\n}\n\nexport default class SlimSelect {\n public selectEl: HTMLSelectElement\n\n // Classes\n public settings!: Settings\n public cssClasses!: CssClasses\n public select!: Select\n public store!: Store\n public render!: Render\n public sync!: SyncCoordinator\n public lifecycle!: Lifecycle\n private globalEvents!: GlobalEvents\n /** Invalidates in-flight API search responses when the query changes or clears. */\n private searchGeneration = 0\n\n // Events\n public events = {\n search: undefined,\n searchFilter: (opt: Option, search: string) => {\n return opt.text.toLowerCase().indexOf(search.toLowerCase()) !== -1\n },\n addable: undefined,\n beforeChange: undefined,\n afterChange: undefined,\n beforeOpen: undefined,\n afterOpen: undefined,\n beforeClose: undefined,\n afterClose: undefined\n } as Events\n\n constructor(config: Config) {\n // Make sure you get the right element\n this.selectEl = (\n typeof config.select === 'string'\n ? document.querySelector(config.select)\n : config.select\n ) as HTMLSelectElement\n if (!this.selectEl) {\n if (config.events && config.events.error) {\n config.events.error(new Error('Could not find select element'))\n }\n return\n }\n if (this.selectEl.tagName !== 'SELECT') {\n if (config.events && config.events.error) {\n config.events.error(new Error('Element isnt of type select'))\n }\n return\n }\n\n // If select already has a slim select id on it lets destroy it first\n if (this.selectEl.dataset.ssid) {\n this.destroy()\n }\n\n // Set settings\n this.settings = new Settings(config.settings)\n\n // Set CSS classes\n this.cssClasses = new CssClasses(config.cssClasses)\n\n // Set events\n const debounceEvents = ['beforeOpen', 'afterOpen', 'afterClose']\n for (const key in config.events) {\n // Check if key exists in events\n if (!config.events.hasOwnProperty(key)) {\n continue\n }\n\n // Check if key is in debounceEvents\n if (debounceEvents.indexOf(key) !== -1) {\n ;(this.events as { [key: string]: any })[key] = debounce(\n (config.events as { [key: string]: any })[key],\n 100\n )\n } else {\n ;(this.events as { [key: string]: any })[key] = (\n config.events as { [key: string]: any }\n )[key]\n }\n }\n\n // Upate settings with type, style and classname\n this.settings.disabled = config.settings?.disabled\n ? config.settings.disabled\n : this.selectEl.disabled\n this.settings.isMultiple = this.selectEl.multiple\n this.settings.style = this.selectEl.style.cssText\n this.settings.class = this.selectEl.className.split(' ')\n\n // Set select class\n this.select = new Select(this.selectEl)\n // Ensure the select has an id for label associations\n if (!this.selectEl.id) {\n this.selectEl.id = this.settings.id\n }\n this.select.updateSelect(\n this.settings.id,\n this.settings.style,\n this.settings.class\n )\n this.select.hideUI() // Hide the original select element\n\n this.select.onClassChange = (classes: string[]) => {\n // Update settings with new class\n this.settings.class = classes\n\n // Run render updateClassStyles\n this.render.updateClassStyles()\n }\n this.select.onDisabledChange = (disabled: boolean) => {\n if (disabled) {\n this.disable()\n } else {\n this.enable()\n }\n }\n\n // Set up label click handler to toggle SlimSelect\n // This allows clicking the label to open/close, matching the main div behavior\n this.select.onLabelClick = () => {\n if (!this.settings.disabled) {\n this.settings.isOpen\n ? this.close({ source: 'toggle', selectionChanged: false })\n : this.open()\n }\n }\n\n // Set store class\n const data = config.data ? config.data : this.select.getData()\n this.store = new Store(\n this.settings.isMultiple ? 'multiple' : 'single',\n data\n )\n\n // If data is passed update the original select element\n if (config.data) {\n this.select.updateOptions(this.store.getData())\n }\n\n // Set render renderCallbacks\n const renderCallbacks = {\n open: this.open.bind(this),\n close: this.close.bind(this),\n addable: this.events.addable ? this.events.addable : undefined,\n // UI clicks route through SyncCoordinator (batched, avoids double updates)\n setSelected: (values: string | string[], runAfterChange: boolean) => {\n this.sync.enqueue({\n type: 'selection',\n values,\n source: 'ui',\n runAfterChange\n })\n },\n addOption: (option: Partial<Option>) => {\n this.sync.enqueue({\n type: 'addOption',\n option,\n source: 'ui'\n })\n },\n search: this.search.bind(this),\n beforeChange: this.events.beforeChange,\n afterChange: this.events.afterChange\n }\n\n // Setup render class\n this.settings.modalTitle =\n config.settings?.modalTitle ?? getAssociatedLabelText(this.selectEl)\n\n this.render = new Render(\n this.settings,\n this.cssClasses,\n this.store,\n renderCallbacks\n )\n\n // Align JS timeout with --ss-animation-timing (CSS is source of truth)\n this.settings.timeoutDelay = getAnimationTimeout(\n this.render.content.main,\n config.settings?.timeoutDelay\n )\n\n // Single coordinator batches native + API + UI updates (see sync.ts)\n this.sync = new SyncCoordinator({\n select: this.select,\n store: this.store,\n render: this.render,\n events: this.events,\n search: this.search.bind(this)\n })\n\n this.select.onValueChange = (options: Option[]) => {\n this.sync.enqueue({\n type: 'selection',\n values: options.map((option) => option.id),\n source: 'native'\n })\n }\n this.select.onOptionsChange = (data: (Option | Optgroup)[]) => {\n this.sync.enqueue({\n type: 'structure',\n data: data || [],\n source: 'native'\n })\n }\n\n // Open/close state machine — animation wait + outside-click attach timing\n this.lifecycle = new Lifecycle(\n {\n beforeOpen: this.events.beforeOpen,\n afterOpen: this.events.afterOpen,\n beforeClose: (info) => this.events.beforeClose?.(info),\n onClose: (info) => this.applyClose(info),\n afterClose: () => {\n this.render.clearDirectionClasses()\n this.render.finalizeModalClose()\n if (this.events.afterClose) {\n this.events.afterClose()\n }\n },\n onOpenReady: () => this.globalEvents.attachDocumentClick(),\n onCloseReady: () => this.globalEvents.detachDocumentClick()\n },\n {\n timeoutDelay: this.settings.timeoutDelay,\n waitForAnimation: (phase, signal) =>\n this.render.waitForAnimation(phase, signal)\n }\n )\n\n // Resize/scroll/visibility listeners (document click via lifecycle onOpenReady)\n this.globalEvents = new GlobalEvents({\n onDocumentClick: this.documentClick.bind(this),\n onWindowResize: () => {\n if (!this.settings.isOpen && !this.settings.isFullOpen) {\n return\n }\n this.render.moveContent()\n },\n onWindowScroll: () => {\n if (!this.settings.isOpen && !this.settings.isFullOpen) {\n return\n }\n this.render.moveContent()\n },\n onVisibilityChange: () => {\n if (document.hidden) {\n this.close({ source: 'api', selectionChanged: false })\n }\n }\n })\n\n this.render.renderValues()\n this.render.renderOptions(this.store.getData(false))\n\n // Add aria-label or aria-labelledby if exists\n const selectAriaLabel = this.selectEl.getAttribute('aria-label')\n const selectAriaLabelledBy = this.selectEl.getAttribute('aria-labelledby')\n\n if (selectAriaLabel) {\n this.render.main.main.setAttribute('aria-label', selectAriaLabel)\n } else if (selectAriaLabelledBy) {\n this.render.main.main.removeAttribute('aria-label')\n this.render.main.main.setAttribute(\n 'aria-labelledby',\n selectAriaLabelledBy\n )\n } else if (this.selectEl.labels && this.selectEl.labels.length > 0) {\n const labelledByIds = Array.from(this.selectEl.labels).map((label, i) => {\n if (!label.id) {\n label.id = `${this.settings.id}-label-${i}`\n }\n return label.id\n })\n this.render.main.main.removeAttribute('aria-label')\n this.render.main.main.setAttribute(\n 'aria-labelledby',\n labelledByIds.join(' ')\n )\n }\n\n // Add render after original select element\n if (this.selectEl.parentNode) {\n this.selectEl.parentNode.insertBefore(\n this.render.main.main,\n this.selectEl.nextSibling\n )\n }\n\n this.globalEvents.attach({\n listenScroll: this.settings.openPosition === 'auto'\n })\n\n // If disabled lets call it\n if (this.settings.disabled) {\n this.disable()\n }\n\n // If alwaysOpnen then open it\n if (this.settings.alwaysOpen) {\n this.open()\n }\n\n // Set up label handlers to open SlimSelect when label is clicked\n this.select.setupLabelHandlers()\n\n // Add SlimSelect to select element\n ;(this.selectEl as any).slim = this\n }\n\n // Set to enabled and remove disabled classes\n public enable(): void {\n this.settings.disabled = false\n\n this.select.enable()\n this.render.enable()\n }\n\n // Set to disabled and add disabled classes\n public disable(): void {\n this.settings.disabled = true\n\n this.select.disable()\n this.render.disable()\n }\n\n public getData(): Option[] | Optgroup[] {\n return this.store.getData()\n }\n\n public setData(data: (Partial<Option> | Partial<Optgroup>)[]): void {\n // Batched structure sync — rebuilds native select, store, and option list\n this.sync.enqueue({\n type: 'structure',\n data,\n source: 'api'\n })\n }\n\n public getSelected(): string[] {\n let options = this.store.getSelectedOptions()\n if (this.settings.keepOrder) {\n options = this.store.selectedOrderOptions(options)\n }\n return options.map((option) => option.value)\n }\n\n // Will take in a string or array of strings and set the selected by either the id or value\n public setSelected(values: string | string[], runAfterChange = true): void {\n // Lightweight path — store + native + chips only (no full DOM rebuild)\n this.sync.enqueue({\n type: 'selection',\n values,\n source: 'api',\n runAfterChange\n })\n }\n\n public addOption(option: Partial<Option>): void {\n this.sync.enqueue({\n type: 'addOption',\n option,\n source: 'api'\n })\n }\n\n public open(): void {\n // Dont open if disabled\n // Dont do anything if the content is already open\n if (this.settings.disabled || this.settings.isOpen) {\n return\n }\n\n // Cancel in-flight open/close animation wait (rapid toggle)\n this.lifecycle.cancelPending()\n\n // Tell render to open\n this.render.open()\n\n // Focus on input field only if search is enabled\n if (this.settings.showSearch && this.settings.focusSearch) {\n this.render.searchFocus()\n }\n\n this.settings.isOpen = true\n\n // Sync isFullOpen/isOpen after CSS transition (or timeoutDelay fallback)\n void this.lifecycle.requestOpen().then(() => {\n // close() may have run before this async completion (e.g. closeOnSelect)\n if (!this.settings.isOpen) {\n return\n }\n this.settings.isFullOpen = this.lifecycle.isFullOpen\n this.settings.isOpen = this.lifecycle.isOpen\n })\n\n // Reposition when trigger or ancestors resize (absolute content only)\n if (\n this.settings.contentPosition === 'absolute' &&\n !this.render.isModalViewActive()\n ) {\n this.render.startPositionTracking()\n }\n\n const searchValue = this.render.content.search.input.value.trim()\n if (searchValue !== '') {\n this.search(searchValue)\n }\n }\n\n public close(\n info: CloseInfo = { source: 'api', selectionChanged: false }\n ): void {\n // Dont do anything if the content is already closed\n // Dont do anything if alwaysOpen is true\n if (!this.settings.isOpen || this.settings.alwaysOpen) {\n return\n }\n\n void this.lifecycle.requestClose(info).then((closed) => {\n if (!closed) {\n return\n }\n\n // open() may have run before this async completion\n if (this.settings.isOpen) {\n return\n }\n\n this.settings.isOpen = this.lifecycle.isOpen\n this.settings.isFullOpen = this.lifecycle.isFullOpen\n })\n }\n\n /** Sync close — invoked by lifecycle after beforeClose approves. */\n private applyClose(info: CloseInfo): void {\n // Tell render to close\n this.render.close()\n\n // Clear search only if not empty and keepSearch is false\n if (\n !this.settings.keepSearch &&\n this.render.content.search.input.value !== ''\n ) {\n this.sync.flush()\n this.search('') // Clear search\n }\n\n // If we arent tabbing focus back on the main element\n const skipRefocus =\n info.source === 'outside' || info.source === 'toggle'\n this.render.mainFocus(skipRefocus ? 'click' : null)\n\n // Update settings\n this.settings.isOpen = false\n this.settings.isFullOpen = false\n\n this.render.stopPositionTracking()\n }\n\n // Take in string value and search current options\n public search(value: string): void {\n const trimmed = value.trim()\n\n if (trimmed === '') {\n this.render.content.search.input.value = ''\n this.clearSearch()\n return\n }\n\n // Sync programmatic search calls, but never strip spaces from user input\n if (this.render.content.search.input.value !== value) {\n this.render.content.search.input.value = value\n }\n\n if (this.events.search) {\n this.runApiSearch(trimmed)\n return\n }\n\n this.runLocalSearch(trimmed)\n }\n\n private clearSearch(): void {\n this.searchGeneration++\n\n if (!this.events.search && this.render.canFilterOptionsInPlace()) {\n this.render.filterOptionsInPlace('', this.events.searchFilter!)\n this.render.resetSearchFilterState()\n return\n }\n\n this.render.resetSearchFilterState()\n this.sync.enqueue({\n type: 'structure',\n data: this.store.getCatalogData(),\n source: 'api',\n preserveSelection: true\n })\n }\n\n private runLocalSearch(value: string): void {\n if (this.render.canFilterOptionsInPlace()) {\n this.render.filterOptionsInPlace(value, this.events.searchFilter!)\n return\n }\n\n const searchResults = this.store.search(value, this.events.searchFilter!)\n this.render.renderOptions(searchResults)\n }\n\n private runApiSearch(value: string): void {\n const generation = ++this.searchGeneration\n this.render.renderSearching()\n\n const searchResp = this.events.search!(\n value,\n this.store.getSelectedOptions(),\n this.store.getCatalogData()\n )\n\n const applyResults = (\n data: (Partial<Option> | Partial<Optgroup>)[]\n ): void => {\n if (generation !== this.searchGeneration) {\n return\n }\n if (this.render.content.search.input.value.trim() !== value) {\n return\n }\n\n this.sync.enqueue({\n type: 'structure',\n data,\n source: 'api',\n preserveSelection: true,\n isSearchResult: true\n })\n }\n\n if (searchResp instanceof Promise) {\n searchResp.then(applyResults).catch((err: Error | string) => {\n if (generation !== this.searchGeneration) {\n return\n }\n this.render.renderError(typeof err === 'string' ? err : err.message)\n })\n\n return\n }\n\n if (Array.isArray(searchResp)) {\n applyResults(searchResp)\n return\n }\n\n this.render.renderError(\n 'Search event must return a promise or an array of data'\n )\n }\n\n public destroy(): void {\n this.lifecycle.destroy()\n\n this.render.stopPositionTracking()\n\n this.globalEvents.detach({\n listenScroll: this.settings.openPosition === 'auto'\n })\n\n // Delete the store data\n this.store.setData([])\n\n // Remove the render\n this.render.destroy()\n\n // Show the original select element\n this.select.destroy()\n\n delete (this.selectEl as HTMLSelectElement & { slim?: SlimSelect }).slim\n }\n\n // Event listener for document click\n private documentClick(e: Event): void {\n // If the content is not open, there is no need to close it\n if (!this.settings.isOpen) {\n return\n }\n\n // Check if the click was on the content by looking at the parents\n if (\n e.target &&\n !hasClassInTree(e.target as HTMLElement, this.settings.id)\n ) {\n this.close({ source: 'outside', selectionChanged: false })\n }\n }\n}\n","// UMD entry point - only exports the default SlimSelect class\n// This avoids the mixed exports issue for UMD/IIFE builds\nimport SlimSelect, * as namedExports from './index'\n\n// Attach all named exports as properties on the default export\nObject.assign(SlimSelect, namedExports)\n\nexport default SlimSelect\n"],"mappings":"+KAAqB,EAArB,KAAgC,CAC9B,KAEA,YAGA,OACA,OACA,YACA,IACA,MACA,UACA,YACA,SAGA,SACA,aAGA,MACA,WACA,UAGA,QACA,YACA,SACA,SAGA,OACA,kBACA,UACA,OACA,QACA,YAGA,KAGA,SACA,cACA,kBACA,gBACA,kBACA,qBACA,uBACA,iBAGA,OACA,aACA,YAGA,aACA,YACA,WACA,WACA,aAGA,SACA,MACA,SACA,MACA,SACA,KAEA,YAAY,EAA+B,CACzC,AACE,IAAU,CAAC,EAGb,IAAI,GAAQ,EAAI,GAAI,EAAI,KAAO,GAAG,EAAE,GAAG,IAAI,KAAK,EAEhD,KAAK,KAAO,EAAK,UAAW,EAAQ,IAAI,EACxC,KAAK,YAAc,EAAK,iBAAkB,EAAQ,WAAW,EAC7D,KAAK,OAAS,EAAK,YAAa,EAAQ,MAAM,EAC9C,KAAK,OAAS,EAAK,YAAa,EAAQ,MAAM,EAC9C,KAAK,YAAc,EAAK,kBAAmB,EAAQ,WAAW,EAC9D,KAAK,IAAM,EAAK,SAAU,EAAQ,GAAG,EACrC,KAAK,MAAQ,EAAK,WAAY,EAAQ,KAAK,EAC3C,KAAK,UAAY,EAAK,gBAAiB,EAAQ,SAAS,EACxD,KAAK,YAAc,EAAK,kBAAmB,EAAQ,WAAW,EAC9D,KAAK,SAAW,EAAK,eAAgB,EAAQ,QAAQ,EAErD,KAAK,SAAW,EAAK,cAAe,EAAQ,QAAQ,EACpD,KAAK,aAAe,EAAQ,cAAgB,8BAC5C,KAAK,MAAQ,EAAK,WAAY,EAAQ,KAAK,EAC3C,KAAK,WAAa,EAAQ,YAAc,uBACxC,KAAK,UAAY,EAAQ,WAAa,uBACtC,KAAK,QAAU,EAAK,aAAc,EAAQ,OAAO,EACjD,KAAK,YAAc,EAAK,UAAW,EAAQ,WAAW,EACtD,KAAK,SAAW,EAAK,eAAgB,EAAQ,QAAQ,EACrD,KAAK,SAAW,EAAK,eAAgB,EAAQ,QAAQ,EACrD,KAAK,OAAS,EAAK,YAAa,EAAQ,MAAM,EAC9C,KAAK,kBAAoB,EACvB,sBACA,EAAQ,iBACV,EACA,KAAK,UAAY,EAAK,eAAgB,EAAQ,SAAS,EACvD,KAAK,OAAS,EAAK,YAAa,EAAQ,MAAM,EAC9C,KAAK,QAAU,EAAK,aAAc,EAAQ,OAAO,EACjD,KAAK,YAAc,EAAQ,aAAe,8BAC1C,KAAK,KAAO,EAAK,UAAW,EAAQ,IAAI,EACxC,KAAK,SAAW,EAAK,cAAe,EAAQ,QAAQ,EACpD,KAAK,cAAgB,EAAK,oBAAqB,EAAQ,aAAa,EACpE,KAAK,kBAAoB,EACvB,yBACA,EAAQ,iBACV,EACA,KAAK,gBAAkB,EAAK,sBAAuB,EAAQ,eAAe,EAC1E,KAAK,kBAAoB,EAAK,eAAgB,EAAQ,iBAAiB,EACvE,KAAK,qBACH,EAAQ,sBAAwB,qCAClC,KAAK,uBACH,EAAQ,wBAA0B,uBACpC,KAAK,iBAAmB,EAAK,cAAe,EAAQ,gBAAgB,EACpE,KAAK,OAAS,EAAK,YAAa,EAAQ,MAAM,EAC9C,KAAK,aAAe,EAAQ,cAAgB,8BAC5C,KAAK,YAAc,EAAK,iBAAkB,EAAQ,WAAW,EAC7D,KAAK,aAAe,EAAK,mBAAoB,EAAQ,YAAY,EACjE,KAAK,YAAc,EAAK,kBAAmB,EAAQ,WAAW,EAC9D,KAAK,WAAa,EAAK,iBAAkB,EAAQ,UAAU,EAC3D,KAAK,WAAa,EAAK,iBAAkB,EAAQ,UAAU,EAC3D,KAAK,aAAe,EAAK,mBAAoB,EAAQ,YAAY,EACjE,KAAK,SAAW,EAAK,UAAW,EAAQ,QAAQ,EAChD,KAAK,MAAQ,EAAK,WAAY,EAAQ,KAAK,EAC3C,KAAK,SAAW,EAAK,cAAe,EAAQ,QAAQ,EACpD,KAAK,MAAQ,EAAK,WAAY,EAAQ,KAAK,EAC3C,KAAK,SAAW,EAAK,cAAe,EAAQ,QAAQ,EACpD,KAAK,KAAO,EAAK,UAAW,EAAQ,IAAI,CAC1C,CAEA,SAAgB,EAAkD,CAChE,OAAO,KAAK,EAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAC/B,CACF,ECpIM,EAAsB,IAMf,EAAsC,CACjD,YACA,SACF,EAGA,SAAgB,EACd,EACA,EAAW,EACH,CACR,IAAM,EAAU,EAAS,KAAK,EAC9B,GAAI,CAAC,EACH,OAAO,EAGT,GAAI,EAAQ,SAAS,IAAI,EAAG,CAC1B,IAAM,EAAK,WAAW,CAAO,EAC7B,OAAO,OAAO,MAAM,CAAE,EAAI,EAAW,CACvC,CAEA,GAAI,EAAQ,SAAS,GAAG,EAAG,CACzB,IAAM,EAAU,WAAW,CAAO,EAClC,OAAO,OAAO,MAAM,CAAO,EAAI,EAAW,EAAU,GACtD,CAEA,IAAM,EAAU,WAAW,CAAO,EAClC,OAAO,OAAO,MAAM,CAAO,EAAI,EAAW,CAC5C,CAGA,SAAgB,EACd,EACA,EAAW,EACH,CAKR,OAAO,EAJe,iBAAiB,CACtB,CAAA,CACd,iBAAiB,uBAAuB,CAAC,CACzC,KAC2B,EAAU,CAAQ,CAClD,CAOA,SAAgB,EACd,EACA,EACA,EAAW,EACH,CACR,IAAM,EACJ,EAAqB,EAAS,CAAQ,EAAA,GAMxC,OAJI,IAAgB,IAAA,GACX,EAGF,KAAK,IAAI,EAAS,CAAW,CACtC,CAGA,SAAgB,GAAgC,CAQ9C,OANE,OAAO,OAAW,KAClB,OAAO,OAAO,YAAe,WAEtB,GAGF,OAAO,WAAW,kCAAkC,CAAC,CAAC,OAC/D,CAEA,SAAS,EACP,EACoB,CAMpB,OALI,IAAkB,IAAA,GACb,KAIF,IAAI,IADE,MAAM,QAAQ,CAAa,EAAI,EAAgB,CAAC,CAAa,CACvD,CACrB,CASA,SAAgB,EACd,EACA,EACA,EAAY,EACZ,EACe,CACf,GAAI,EAAqB,GAAK,GAAQ,QACpC,OAAO,QAAQ,QAAQ,EAGzB,IAAM,EAAU,EAA8B,CAAa,EAE3D,OAAO,IAAI,QAAe,GAAY,CACpC,IAAI,EAA8C,KAC9C,EAAU,GAER,MAAe,CACf,IAGJ,EAAU,GACV,EAAQ,oBAAoB,gBAAiB,CAAe,EAC5D,GAAQ,oBAAoB,QAAS,CAAO,EACxC,GACF,aAAa,CAAK,EAEpB,EAAQ,EACV,EAEM,MAAgB,EAAO,EAEvB,EAAmB,GAA2B,CAC9C,EAAM,SAAW,IAIjB,IACE,CAAC,EAAQ,IAAI,EAAM,YAAY,IAGnC,EAAQ,OAAO,EAAM,YAAY,EAC7B,EAAQ,KAAO,KAKrB,EAAO,EACT,EAEA,GAAQ,iBAAiB,QAAS,EAAS,CAAE,KAAM,EAAK,CAAC,EACzD,EAAQ,iBAAiB,gBAAiB,CAAe,EACzD,EAAQ,WAAW,EAAQ,CAAS,CACtC,CAAC,CACH,CAQA,SAAgB,EACd,EACA,EACA,EAAY,EACZ,EACe,CAKf,OAJI,EAAqB,GAAK,GAAQ,QAC7B,QAAQ,QAAQ,EAGlB,IAAI,QAAe,GAAY,CACpC,IAAI,EAA8C,KAC9C,EAAU,GAER,MAAe,CACf,IAGJ,EAAU,GACV,EAAQ,oBAAoB,eAAgB,CAAc,EAC1D,GAAQ,oBAAoB,QAAS,CAAO,EACxC,GACF,aAAa,CAAK,EAEpB,EAAQ,EACV,EAEM,MAAgB,EAAO,EAEvB,EAAkB,GAA0B,CAC5C,EAAM,SAAW,IAGjB,GAAiB,EAAM,gBAAkB,GAG7C,EAAO,EACT,EAEA,GAAQ,iBAAiB,QAAS,EAAS,CAAE,KAAM,EAAK,CAAC,EACzD,EAAQ,iBAAiB,eAAgB,CAAc,EACvD,EAAQ,WAAW,EAAQ,CAAS,CACtC,CAAC,CACH,CC3MA,IAAqB,EAArB,KAA8B,CAC5B,GAAoB,GACpB,MAAuB,GACvB,MAAyB,CAAC,EAG1B,WAA6B,GAC7B,OAAyB,GACzB,WAA6B,GAG7B,SACA,WACA,WACA,YACA,WACA,UACA,kBACA,WACA,cACA,YACA,aACA,WACA,gBACA,cACA,gBACA,gBACA,aACA,aACA,gBACA,cACA,aACA,YACA,UACA,mBACA,YACA,YACA,aACA,eACA,iBACA,YACA,MACA,WAEA,YAAY,EAA8B,CACxC,AACE,IAAW,CAAC,EAGd,KAAK,GAAK,MAAQ,EAAW,EAC7B,KAAK,MAAQ,EAAS,OAAS,GAC/B,KAAK,MAAQ,EAAS,OAAS,CAAC,EAEhC,KAAK,SAAW,EAAS,WAAa,IAAA,IAAY,EAAS,SAC3D,KAAK,WACH,EAAS,aAAe,IAAA,IAAY,EAAS,WAC/C,KAAK,WACH,EAAS,aAAe,IAAA,IAAY,EAAS,WAC/C,KAAK,YACH,EAAS,cAAgB,IAAA,IAAY,EAAS,YAChD,KAAK,WACH,EAAS,aAAe,IAAA,IAAY,EAAS,WAC/C,KAAK,UAAY,EAAS,WAAa,WACvC,KAAK,kBAAoB,EAAS,mBAAqB,YACvD,KAAK,WAAa,EAAS,YAAc,aACzC,KAAK,cAAgB,EAAS,eAAiB,eAC/C,KAAK,YAAc,EAAS,aAAe,4BAC3C,KAAK,aAAe,EAAS,cAAgB,QAC7C,KAAK,WAAa,EAAS,YAAc,SACzC,KAAK,gBACH,EAAS,kBAAoB,IAAA,IAAY,EAAS,gBACpD,KAAK,cACH,EAAS,gBAAkB,IAAA,IAAY,EAAS,cAClD,KAAK,gBAAkB,EAAS,iBAAmB,SAAS,KAC5D,KAAK,gBAAkB,EAAS,iBAAmB,WACnD,KAAK,aAAe,EAAS,cAAgB,GAC7C,KAAK,aAAe,EAAS,cAAgB,OAC7C,KAAK,gBACH,EAAS,kBAAoB,IAAA,GAEzB,eADA,EAAS,gBAEf,KAAK,cACH,EAAS,gBAAkB,IAAA,IAAY,EAAS,cAClD,KAAK,aACH,EAAS,eAAiB,IAAA,IAAY,EAAS,aACjD,KAAK,YACH,EAAS,cAAgB,IAAA,IAAY,EAAS,YAChD,KAAK,UACH,EAAS,YAAc,IAAA,IAAY,EAAS,UAC9C,KAAK,mBACH,EAAS,qBAAuB,IAAA,IAC5B,EAAS,mBAEf,KAAK,YAAc,EAAS,aAAe,EAC3C,KAAK,YAAc,EAAS,aAAe,IAC3C,KAAK,aAAe,EAAS,cAAgB,IAC7C,KAAK,eAAiB,EAAS,gBAAkB,GACjD,KAAK,iBAAmB,EAAS,kBAAoB,oBACrD,KAAK,YAAc,EAAS,aAAe,+BAC3C,KAAK,MAAQ,EAAS,OAAS,SAC/B,KAAK,WAAa,EAAS,YAAc,EAC3C,CACF,ECtGA,SAAgB,EACd,EAC2B,CAC3B,GAAI,CAAC,EACH,MAAO,CAAC,EAGV,IAAM,EAAoC,CAAC,EAC3C,IAAK,IAAM,KAAO,OAAO,KAAK,CAAI,EAAG,CACnC,IAAM,EAAQ,EAAK,GACf,IAAU,IAAA,KACZ,EAAO,GAAO,EAElB,CACA,OAAO,CACT,CAGA,SAAgB,EAAoB,EAAiC,CACnE,IAAM,EAAQ,EAAM,UAAU,EAAI,EAKlC,OAJA,EACG,iBAAiB,mDAAmD,CAAC,CACrE,QAAS,GAAO,EAAG,OAAO,CAAC,EAEvB,EAAM,aAAa,QAAQ,OAAQ,GAAG,CAAC,CAAC,KAAK,GAAK,EAC3D,CAGA,SAAgB,EAAuB,EAAmC,CACxE,GAAI,EAAO,QAAU,EAAO,OAAO,OAAS,EAAG,CAC7C,IAAM,EAAQ,MAAM,KAAK,EAAO,MAAM,CAAC,CACpC,IAAI,CAAmB,CAAC,CACxB,OAAO,OAAO,EAEjB,GAAI,EAAM,OAAS,EACjB,MAAO,CAAC,GAAG,IAAI,IAAI,CAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAEvC,CAEA,OAAO,EAAO,aAAa,YAAY,CAAC,EAAE,KAAK,GAAK,EACtD,CAGA,SAAgB,GAAqB,CACnC,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,UAAU,EAAG,EAAE,CACnD,CAEA,SAAgB,EACd,EACA,EACoB,CACpB,SAAS,EAAS,EAAgB,EAAW,CAW3C,OATI,GAAK,GAAK,EAAE,WAAa,EAAE,UAAU,SAAS,CAAC,GAK/C,GAAK,GAAK,EAAE,SAAW,EAAE,QAAQ,IAAM,EAAE,QAAQ,KAAO,EACnD,EAGF,IACT,CAEA,SAAS,EAAc,EAAQ,EAAgB,CAM3C,MALE,CAAC,GAAK,IAAO,SACR,KACE,EAAS,EAAG,CAAC,EACf,EAEA,EAAc,EAAE,WAAY,CAAC,CAExC,CAEA,OAAO,EAAS,EAAS,CAAS,GAAK,EAAc,EAAS,CAAS,CACzE,CAGA,SAAgB,EACd,EACA,EAAO,GACP,EAAY,GACA,CACZ,IAAI,EACJ,OAAO,SAAqB,GAAG,EAAmB,CAChD,IAAM,EAAU,KACV,MAAc,CAClB,EAAU,KACL,GACH,EAAK,MAAM,EAAS,CAAI,CAE5B,EACM,EAAU,GAAa,CAAC,EAC9B,aAAa,CAAO,EACpB,EAAU,WAAW,EAAO,CAAI,EAC5B,GACF,EAAK,MAAM,EAAS,CAAI,CAE5B,CACF,CAOA,SAAgB,EAAiB,EAAa,EAAsB,CAClE,GAAI,EAAE,SAAW,EAAE,OACjB,MAAO,GAGT,IAAM,EAAU,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EACtB,EAAU,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAC5B,OAAO,EAAQ,OAAO,EAAI,IAAM,IAAO,EAAQ,EAAE,CACnD,CAEA,IAAM,EAAgB,CACpB,KACA,QACA,OACA,OACA,kBACA,WACA,UACA,WACA,cACA,QACA,QACA,WACF,EAEA,SAAS,EACP,EACA,EACS,CACT,IAAM,EAAQ,OAAO,KAAK,CAAC,EACrB,EAAQ,OAAO,KAAK,CAAC,EAE3B,GAAI,EAAM,SAAW,EAAM,OACzB,MAAO,GAGT,IAAK,IAAM,KAAO,EAChB,GAAI,EAAE,KAAS,EAAE,GACf,MAAO,GAIX,MAAO,EACT,CAEA,SAAS,EACP,EACA,EAC2C,CAC3C,OAAQ,EAAR,CACE,IAAK,KACH,OAAO,EAAO,IAAM,GACtB,IAAK,QACH,OAAO,EAAO,QAAU,IAAA,GAAY,EAAO,MAAQ,GAAK,EAAO,OAAS,GAC1E,IAAK,OACH,OAAO,EAAO,MAAQ,GACxB,IAAK,OACH,OAAO,EAAO,MAAQ,GACxB,IAAK,kBACH,OAAO,EAAO,iBAAmB,GACnC,IAAK,WACH,OAAO,EAAO,UAAY,GAC5B,IAAK,UACH,OAAO,EAAO,SAAW,GAC3B,IAAK,WACH,OAAO,EAAO,UAAY,GAC5B,IAAK,cACH,OAAO,EAAO,aAAe,GAC/B,IAAK,QACH,OAAO,EAAO,OAAS,GACzB,IAAK,QACH,OAAO,EAAO,OAAS,GACzB,IAAK,YACH,OAAO,EAAO,WAAa,GAC7B,QACE,OAAO,EAAO,MAAQ,CAAC,CAC3B,CACF,CAEA,SAAS,EAAe,EAA2C,CACjE,MACE,CAAC,CAAC,GAAQ,OAAO,GAAS,UAAY,UAAW,GAAQ,YAAa,CAE1E,CAEA,SAAS,EAAqB,EAAoB,EAA6B,CAC7E,IAAK,IAAM,KAAS,EAIlB,GAHW,EAAsB,EAAG,CAGhC,IAFO,EAAsB,EAAG,CAEzB,EACT,MAAO,GAIX,OAAO,EAAmB,EAAE,MAAQ,CAAC,EAAG,EAAE,MAAQ,CAAC,CAAC,CACtD,CAEA,SAAS,EACP,EACA,EACS,CACT,IAAM,EAAc,IAAiC,CACnD,GAAI,EAAS,IAAM,GACnB,MAAO,EAAS,OAAS,GACzB,UAAW,EAAS,WAAa,GACjC,SAAU,EAAS,UAAY,KACjC,GAEM,EAAc,EAAW,CAAC,EAC1B,EAAc,EAAW,CAAC,EAEhC,GACE,EAAY,KAAO,EAAY,IAC/B,EAAY,QAAU,EAAY,OAClC,EAAY,YAAc,EAAY,WACtC,EAAY,WAAa,EAAY,SAErC,MAAO,GAGT,IAAM,EAAW,EAAE,SAAW,CAAC,EACzB,EAAW,EAAE,SAAW,CAAC,EAE/B,GAAI,EAAS,SAAW,EAAS,OAC/B,MAAO,GAGT,IAAK,IAAI,EAAI,EAAG,EAAI,EAAS,OAAQ,IACnC,GAAI,CAAC,EAAqB,EAAS,GAAI,EAAS,EAAE,EAChD,MAAO,GAIX,MAAO,EACT,CAGA,SAAgB,EAAmB,EAAe,EAAwB,CACxE,GAAI,IAAM,EACR,MAAO,GAGT,GAAI,EAAE,SAAW,EAAE,OACjB,MAAO,GAGT,IAAK,IAAI,EAAI,EAAG,EAAI,EAAE,OAAQ,IAAK,CACjC,IAAM,EAAQ,EAAE,GACV,EAAQ,EAAE,GACV,EAAc,EAAe,CAAK,EAGxC,GAAI,IAFgB,EAAe,CAEf,EAClB,MAAO,GAGT,GAAI,EAAa,CACf,GAAI,CAAC,EAAuB,EAAO,CAAK,EACtC,MAAO,GAET,QACF,CAEA,GACE,CAAC,EAAqB,EAA0B,CAAwB,EAExE,MAAO,EAEX,CAEA,MAAO,EACT,CAEA,SAAgB,EAAU,EAAqB,CAC7C,IAAM,EAAS,EAAI,QACjB,mCACC,GAAU,IAAM,EAAM,YAAY,CACrC,EACA,OAAO,EAAI,KAAO,EAAI,EAAE,CAAC,YAAY,EAAI,EAAO,UAAU,CAAC,EAAI,CACjE,CAEA,SAAgB,EACd,EACA,EAAwB,OAAO,OAAW,IACtC,OAAO,WAAA,IAEF,CAOT,OANI,IAAU,MAGV,IAAU,UACL,EAAA,GAGX,CCnSA,IAAqB,EAArB,KAAkC,CAGZ,SAFpB,SAAmB,GAEnB,YAAY,EAAuC,CAA/B,KAAA,SAAA,CAAgC,CAGpD,OAAc,EAA0C,CAClD,KAAK,WAIT,KAAK,SAAW,GAChB,OAAO,iBAAiB,SAAU,KAAK,cAAe,EAAK,EAGvD,EAAQ,cACV,OAAO,iBAAiB,SAAU,KAAK,cAAe,EAAK,EAG7D,SAAS,iBAAiB,mBAAoB,KAAK,iBAAiB,EACtE,CAGA,qBAAmC,CACjC,SAAS,iBAAiB,QAAS,KAAK,SAAS,eAAe,CAClE,CAEA,qBAAmC,CACjC,SAAS,oBAAoB,QAAS,KAAK,SAAS,eAAe,CACrE,CAEA,OAAc,EAA0C,CACjD,KAAK,WAIV,KAAK,SAAW,GAChB,KAAK,oBAAoB,EACzB,OAAO,oBAAoB,SAAU,KAAK,cAAe,EAAK,EAE1D,EAAQ,cACV,OAAO,oBAAoB,SAAU,KAAK,cAAe,EAAK,EAGhE,SAAS,oBAAoB,mBAAoB,KAAK,iBAAiB,EACzE,CAEA,cAAwB,MAAe,CACrC,KAAK,SAAS,eAAe,CAC/B,CAAC,EAED,cAAwB,MAAe,CACrC,KAAK,SAAS,eAAe,CAC/B,CAAC,EAED,sBAAkC,CAChC,KAAK,SAAS,mBAAmB,CACnC,CACF,EChCqB,EAArB,KAA+B,CAUnB,SACA,QAVV,MAA+B,SAC/B,aAA6D,KAE7D,cAA2C,CAAC,EAE5C,WAAqB,EACrB,eAAiD,KAEjD,YACE,EACA,EACA,CAFQ,KAAA,SAAA,EACA,KAAA,QAAA,CACP,CAEH,IAAW,QAAkB,CAC3B,OAAO,KAAK,QAAU,WAAa,KAAK,QAAU,MACpD,CAEA,IAAW,YAAsB,CAC/B,OAAO,KAAK,QAAU,MACxB,CAEA,MAAa,aAA6B,CACxC,GAAI,KAAK,QAAU,WAAa,KAAK,QAAU,OAC7C,OAGF,KAAK,cAAc,EACnB,IAAM,EAAM,EAAE,KAAK,WAUnB,GARI,KAAK,SAAS,YAChB,KAAK,SAAS,WAAW,EAG3B,KAAK,MAAQ,UACb,MAAM,KAAK,aAAa,OAAQ,CAAG,EAG/B,IAAQ,KAAK,WAAY,CACvB,KAAK,QAAU,YACjB,KAAK,MAAQ,UAEf,MACF,CAEA,KAAK,MAAQ,OAET,KAAK,SAAS,WAChB,KAAK,SAAS,UAAU,EAGtB,KAAK,SAAS,aAChB,KAAK,SAAS,YAAY,CAE9B,CAEA,MAAa,aACX,EAAkB,CAAE,OAAQ,MAAO,iBAAkB,EAAM,EACzC,CAKlB,GAJI,KAAK,QAAU,UAAY,KAAK,QAAU,WAI1C,KAAK,SAAS,aAAe,KAAK,SAAS,YAAY,CAAI,IAAM,GACnE,MAAO,GAGT,KAAK,cAAc,EACnB,IAAM,EAAM,EAAE,KAAK,WAuBnB,OArBI,KAAK,SAAS,SAChB,KAAK,SAAS,QAAQ,CAAI,EAG5B,KAAK,MAAQ,UACb,MAAM,KAAK,aAAa,QAAS,CAAG,EAEhC,IAAQ,KAAK,YAIjB,KAAK,MAAQ,SAET,KAAK,SAAS,YAChB,KAAK,SAAS,WAAW,EAGvB,KAAK,SAAS,cAChB,KAAK,SAAS,aAAa,EAGtB,IAbE,EAcX,CAGA,eAA6B,CAC3B,KAAK,aACL,KAAK,gBAAgB,MAAM,EAC3B,KAAK,eAAiB,KACtB,AAEE,KAAK,gBADL,aAAa,KAAK,YAAY,EACV,MAEtB,IAAM,EAAY,KAAK,cAAc,OAAO,CAAC,EAC7C,IAAK,IAAM,KAAW,EACpB,EAAQ,CAEZ,CAEA,SAAuB,CACrB,KAAK,cAAc,EACnB,KAAK,MAAQ,QACf,CAMA,aACE,EACA,EACe,CACf,OAAO,IAAI,QAAe,GAAY,CACpC,IAAI,EAAU,GACR,MAAe,CACnB,GAAI,EACF,OAEF,EAAU,GACV,IAAM,EAAM,KAAK,cAAc,QAAQ,CAAM,EACzC,IAAQ,IACV,KAAK,cAAc,OAAO,EAAK,CAAC,EAElC,EAAQ,CACV,EAIA,GAFA,KAAK,cAAc,KAAK,CAAM,EAE1B,KAAK,QAAQ,iBAAkB,CACjC,IAAM,EAAa,IAAI,gBACvB,KAAK,eAAiB,EACtB,KAAU,QACP,iBAAiB,EAAO,EAAW,MAAM,CAAC,CAC1C,UAAY,IAAA,EAAS,CAAC,CACtB,YAAc,CACT,KAAK,iBAAmB,IAC1B,KAAK,eAAiB,MAExB,EAAO,CACT,CAAC,CACL,KACE,MAAK,aAAe,eAAiB,CACnC,KAAK,aAAe,KACpB,EAAO,CACT,EAAG,KAAK,QAAQ,YAAY,CAEhC,CAAC,CAAC,CAAC,SAAW,CACA,KAAK,UAGnB,CAAC,CACH,CACF,EC3Ma,EAAb,KAAoB,CAClB,GACA,MACA,KACA,KACA,gBACA,SACA,QACA,SACA,YACA,MACA,MACA,KACA,UAEA,YAAY,EAAyB,CACnC,KAAK,GAAK,CAAC,EAAO,IAAM,EAAO,KAAO,GAAK,EAAW,EAAI,EAAO,GACjE,KAAK,MACH,EAAO,QAAU,IAAA,GAAY,EAAO,MAAQ,GAAK,EAAO,OAAS,GACnE,KAAK,KAAO,EAAO,MAAQ,GAC3B,KAAK,KAAO,EAAO,MAAQ,GAC3B,KAAK,gBACH,EAAO,kBAAoB,IAAA,IAAY,EAAO,gBAChD,KAAK,SAAW,EAAO,WAAa,IAAA,IAAY,EAAO,SACvD,KAAK,QAAU,EAAO,UAAY,IAAA,IAAY,EAAO,QACrD,KAAK,SAAW,EAAO,WAAa,IAAA,IAAY,EAAO,SACvD,KAAK,UAAY,EAAO,YAAc,IAAA,IAAY,EAAO,UACzD,KAAK,YACH,EAAO,cAAgB,IAAA,IAAY,EAAO,YAC5C,KAAK,MAAQ,EAAO,OAAS,GAC7B,KAAK,MAAQ,EAAO,OAAS,GAC7B,KAAK,KAAO,EAAe,EAAO,IAAI,CACxC,CACF,EACa,EAAb,KAAsB,CACpB,GACA,MACA,UACA,SACA,QAEA,YAAY,EAA6B,CAUvC,GATA,KAAK,GAAK,CAAC,EAAS,IAAM,EAAS,KAAO,GAAK,EAAW,EAAI,EAAS,GACvE,KAAK,MAAQ,EAAS,OAAS,GAC/B,KAAK,UACH,EAAS,YAAc,IAAA,IAAoB,EAAS,UACtD,KAAK,SAAW,EAAS,UAAY,MAIrC,KAAK,QAAU,CAAC,EACZ,EAAS,QACX,IAAK,IAAM,KAAK,EAAS,QACvB,KAAK,QAAQ,KAAK,IAAI,EAAO,CAAC,CAAC,CAGrC,CACF,EAEqB,EAArB,KAA2B,CACzB,WAA4C,SAG5C,KAAsC,CAAC,EACvC,cAAkC,CAAC,EAEnC,QAAgD,KAEhD,YACE,EACA,EACA,CACA,KAAK,WAAa,EAClB,KAAK,QAAQ,CAAI,EACjB,KAAK,gBAAgB,CACvB,CAGA,kBACE,EACc,CACd,GAAI,CAAC,MAAM,QAAQ,CAAI,EACrB,OAAW,MAAM,uBAAuB,EAI1C,IAAK,IAAI,KAAW,EACb,KAGL,GAAI,aAAmB,GAAY,UAAW,EAAS,CACrD,GAAI,EAAE,UAAW,GACf,OAAW,MAAM,4BAA4B,EAG/C,GAAI,YAAa,GAAW,EAAQ,QAClC,IAAK,IAAI,KAAU,EAAQ,QAAS,CAClC,IAAM,EAAkB,KAAK,eAAe,CAAM,EAClD,GAAI,EACF,OAAO,CAEX,CAEJ,MAAO,GAAI,aAAmB,GAAU,SAAU,EAAS,CACzD,IAAM,EAAkB,KAAK,eAAe,CAAO,EACnD,GAAI,EACF,OAAO,CAEX,MACE,OAAW,MAAM,gDAAgD,EAIrE,OAAO,IACT,CAGA,eAAsB,EAAuC,CAK3D,MAJM,SAAU,EAIT,KAHM,MAAM,yBAAyB,CAI9C,CAEA,kBACE,EACuB,CACvB,IAAI,EAAmC,CAAC,EAwBxC,OAvBA,EAAK,QAAS,GAAY,CACnB,KAGL,IAAI,aAAmB,GAAY,UAAW,EAAS,CACrD,IAAI,EAAuB,CAAC,EACxB,YAAa,GAAW,EAAQ,SAClC,EAAQ,QAAQ,QAAS,GAA4B,CACnD,EAAW,KAAK,IAAI,EAAO,CAAM,CAAC,CACpC,CAAC,EAGC,EAAW,OAAS,GACtB,EAAU,KAAK,IAAI,EAAS,CAA4B,CAAC,CAE7D,EAGI,aAAmB,GAAU,SAAU,IACzC,EAAU,KAAK,IAAI,EAAO,CAA0B,CAAC,CAJvD,CAMF,CAAC,EAEM,CACT,CAGA,iBAA+B,CAC7B,KAAK,QAAU,KAAK,UAAU,KAAK,IAAI,CACzC,CAGA,gBAA+C,CAC7C,OAAO,KAAK,UAAU,KAAK,SAAW,KAAK,IAAI,CACjD,CAEA,UAAkB,EAAoD,CACpE,OAAO,EAAK,IAAK,GACX,aAAgB,EACX,IAAI,EAAS,CAClB,GAAI,EAAK,GACT,MAAO,EAAK,MACZ,UAAW,EAAK,UAChB,SAAU,EAAK,SACf,QAAS,EAAK,QAAQ,IAAK,GACzB,IAAI,EAAO,aAAkB,EAAS,CAAE,GAAG,CAAO,EAAI,CAAM,CAC9D,CACF,CAAC,EAGI,IAAI,EAAO,CAAE,GAAI,CAAgB,CAAC,CAC1C,CACH,CAEA,sBACE,EACA,EACS,CAKT,OAJI,EAAU,KAAO,EAAS,IAK5B,EAAS,QAAU,IACnB,EAAU,QAAU,IACpB,EAAU,QAAU,EAAS,KAEjC,CAEA,iBACE,EACA,EACe,CACf,IAAK,IAAM,KAAQ,EAAM,CACvB,GAAI,aAAgB,EAAQ,CAC1B,GAAI,KAAK,sBAAsB,EAAM,CAAQ,EAC3C,OAAO,EAET,QACF,CAEA,IAAK,IAAM,KAAU,EAAK,QACxB,GAAI,KAAK,sBAAsB,EAAQ,CAAQ,EAC7C,OAAO,CAGb,CAEA,OAAO,IACT,CAEA,QACE,EACA,EAA4B,GAC5B,CAEA,IAAM,EAAU,KAAK,kBAAkB,CAAI,EAEvC,EAAwC,CAAC,EAE7C,GAAI,EAAkB,CAEpB,EAA8B,KAAK,mBAAmB,EAGtD,IAAM,EAA4B,CAAC,EACnC,EAA4B,QAAS,GAAmB,CACjD,KAAK,iBAAiB,EAAS,CAAc,GAChD,EAAgB,KAAK,CAAc,CAEvC,CAAC,EAGD,KAAK,KAAO,CAAC,GAAG,EAAiB,GAAG,CAAO,EAE3C,IAAM,EACJ,KAAK,aAAe,UACpB,EAA4B,SAAW,EACnC,EAAc,EAA4B,IAAK,GAAa,CAChE,IAAM,EAAQ,KAAK,iBAAiB,KAAK,KAAM,CAAQ,EACvD,OAAO,EAAQ,EAAM,GAAK,EAAS,EACrC,CAAC,EAED,KAAK,cAAc,KAAM,EAAa,CAAmB,CAC3D,KACE,MAAK,KAAO,EAKV,CAAC,GAAoB,KAAK,aAAe,UAC3C,KAAK,cAAc,KAAM,KAAK,YAAY,EAAG,EAAK,CAEtD,CAGA,QAAe,EAAQ,GAA6B,CAClD,OAAO,KAAK,OAAO,KAAM,GAAM,CAAK,CACtC,CAGA,eAAsB,EAAQ,GAAgB,CAC5C,OAAO,KAAK,OAAO,KAAM,GAAO,CAAK,CACvC,CAEA,UAAiB,EAAyB,EAAsB,GAAO,CACrE,GAAI,EAAY,CACd,IAAI,EAAO,CAAC,IAAI,EAAO,CAAM,CAAC,EAC9B,KAAK,QAAQ,EAAK,OAAO,KAAK,QAAQ,CAAC,CAAC,CAC1C,MACE,KAAK,QAAQ,KAAK,QAAQ,CAAC,CAAC,OAAO,IAAI,EAAO,CAAM,CAAC,CAAC,CAE1D,CAMA,cACE,EACA,EACA,EAA+B,GAC/B,CACA,IAAI,EAAsC,KACtC,EAAc,GACZ,EAAqC,CAAC,EAE5C,IAAK,IAAI,KAAW,KAAK,KAAM,CAE7B,GAAI,aAAmB,EACrB,IAAK,IAAI,KAAU,EAAQ,QAA8B,CACvD,AACE,IAAc,EAGhB,IAAI,EAAc,EAAO,IAAiB,GAC1C,EAAO,SAAW,IAEd,EAAe,SAAS,CAAW,EAInC,EAAO,WACT,EAAgB,KAAK,CAAM,EAEvB,KAAK,aAAe,WACtB,EAAc,IAGpB,CAIE,aAAmB,IACrB,AACE,IAAc,EAGhB,EAAQ,SAAW,IAEf,EAAe,SAAS,EAAQ,EAAa,EAI7C,EAAQ,WACV,EAAgB,KAAK,CAAO,EAExB,KAAK,aAAe,WACtB,EAAc,KAItB,CAIE,KAAK,aAAe,UACpB,GACA,CAAC,GACD,CAAC,IAED,EAAY,SAAW,GACvB,EAAgB,KAAK,CAAW,GAIlC,IAAM,EAAc,EAAe,IAAK,GAEpC,EAAgB,KAAM,GAAW,EAAO,KAAkB,CAAK,CAAC,EAAE,IAClE,EAEH,EAED,KAAK,cAAgB,CACvB,CAEA,aAA+B,CAC7B,OAAO,KAAK,mBAAmB,CAAC,CAAC,IAAK,GAAW,EAAO,EAAE,CAC5D,CAEA,mBAAqC,CACnC,OAAO,KAAK,mBAAmB,CAAC,CAAC,IAAK,GAAW,EAAO,KAAK,CAC/D,CAEA,oBAAsC,CACpC,IAAM,EAAqB,CAAC,EAE5B,IAAK,IAAM,KAAW,KAAK,KACzB,GAAI,aAAmB,MAChB,IAAM,KAAU,EAAQ,QACvB,EAAO,UACT,EAAS,KAAK,CAAM,OAGf,EAAQ,UACjB,EAAS,KAAK,CAAO,EAIzB,OAAO,CACT,CAEA,gBAAuB,EAA6B,CAGlD,IAAK,IAAI,KAAW,KAAK,KACvB,GAAI,aAAmB,GAAY,EAAQ,KAAO,EAChD,OAAO,EAIX,OAAO,IACT,CAEA,cAAqB,EAA2B,CAC9C,IAAK,IAAM,KAAW,KAAK,KACzB,GAAI,aAAmB,OAChB,IAAM,KAAU,EAAQ,QAC3B,GAAI,EAAO,KAAO,EAChB,OAAO,CAAA,MAGN,GAAI,EAAQ,KAAO,EACxB,OAAO,EAIX,OAAO,IACT,CAEA,eAA+B,CAC7B,OAAO,KAAK,UACd,CAEA,gBAAuC,CACrC,IAAI,EAAwB,KAC5B,IAAK,IAAI,KAAW,KAAK,KAOvB,GANI,aAAmB,EACrB,EAAS,EAAQ,QAAQ,GAChB,aAAmB,IAC5B,EAAS,GAGP,EACF,MAGJ,OAAO,CACT,CAGA,OACE,EACA,EACuB,CASvB,MARA,GAAS,EAAO,KAAK,EAGjB,IAAW,GACN,KAAK,QAAQ,EAAK,EAIpB,KAAK,OAAQ,GACX,EAAa,EAAK,CAAM,EAC9B,GAAM,EAAK,CAChB,CAEA,mBACE,EACA,EACU,CACV,IAAM,EAAO,IAAI,EAAS,CACxB,GAAI,EAAO,GACX,MAAO,EAAO,MACd,UAAW,EAAO,UAClB,SAAU,EAAO,SACjB,QAAS,CAAC,CACZ,CAAC,EAED,MADA,GAAK,QAAU,EACR,CACT,CAIA,OACE,EACA,EACA,EAAQ,GACe,CACvB,IAAM,EAAoC,CAAC,EAuC3C,OAtCA,KAAK,KAAK,QAAS,GAA+B,CAEhD,GAAI,aAAmB,EAAU,CAC/B,IAAI,EAAuB,CAAC,EAgB5B,GAdA,EADsB,QACd,QAAS,GAAmB,EAC9B,CAAC,GAAU,EAAO,CAAgB,KAG/B,EAGH,EAAW,KAAK,EAAQ,IAAI,EAAO,CAAM,EAAI,CAAM,EAFnD,EAAW,KAAK,EAAQ,IAAI,EAAO,CAAM,EAAI,CAAM,EAKzD,CAAC,EAIG,EAAW,OAAS,EACtB,GAAI,EAAO,CACT,IAAI,EAAW,IAAI,EAAS,CAAO,EACnC,EAAS,QAAU,EACnB,EAAW,KAAK,CAAQ,CAC1B,MACE,EAAW,KAAK,KAAK,mBAAmB,EAAS,CAAU,CAAC,CAGlE,CAGI,aAAmB,IACjB,CAAC,GAAU,EAAO,CAAO,IAC3B,EAAW,KAAK,EAAQ,IAAI,EAAO,CAAO,EAAI,CAAO,CAG3D,CAAC,EAEM,CACT,CAGA,qBAA4B,EAA6B,CACvD,IAAM,EAAqB,CAAC,EAwB5B,OAvBA,KAAK,cAAc,QAAS,GAAO,CACjC,IAAM,EAAS,EAAQ,KAAM,GAAQ,EAAI,KAAO,CAAE,EAC9C,GACF,EAAS,KAAK,CAAM,CAExB,CAAC,EAGD,EAAQ,QAAS,GAAW,CAC1B,IAAI,EAAO,GACX,EAAS,QAAS,GAAmB,CACnC,GAAI,EAAO,KAAO,EAAe,GAAI,CACnC,EAAO,GAEP,MACF,CACF,CAAC,EAEI,GACH,EAAS,KAAK,CAAM,CAExB,CAAC,EAEM,CACT,CACF,ECjdqB,EAArB,KAA4B,CAC1B,SACA,MACA,UAGA,mBACA,oBACA,sBAAgC,GAChC,qBAA+B,GAK/B,KACA,QAGA,QAEA,iBAAkD,KAClD,oBAA8B,EAC9B,iBAA2B,EAE3B,cAA8C,KAC9C,mBAA6C,KAC7C,iBAA2B,GAC3B,kBAA4B,GAE5B,YACE,EACA,EACA,EACA,EACA,CACA,KAAK,MAAQ,EACb,KAAK,SAAW,EAChB,KAAK,QAAU,EACf,KAAK,UAAY,EACjB,KAAK,mBAAqB,KAC1B,KAAK,oBAAsB,CAAC,EAE5B,KAAK,KAAO,KAAK,QAAQ,EACzB,KAAK,QAAU,KAAK,WAAW,EAG/B,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAMtB,KAAK,SAAS,kBAAoB,aACpC,KAAK,QAAQ,KAAK,MAAM,IAAM,UAC9B,KAAK,QAAQ,KAAK,MAAM,KAAO,UAC/B,KAAK,QAAQ,KAAK,MAAM,OAAS,IACjC,KAAK,QAAQ,KAAK,MAAM,MAAQ,QAI9B,KAAK,SAAS,iBAChB,KAAK,SAAS,gBAAgB,YAAY,KAAK,QAAQ,IAAI,EAGzD,KAAK,SAAS,QAAU,OAAS,CAAC,KAAK,SAAS,aAClD,KAAK,cAAgB,KAAK,oBAAoB,EAC9C,SAAS,KAAK,YAAY,KAAK,cAAc,OAAO,EAExD,CAIA,aACE,EACA,EACM,CACN,KAAK,UAAU,MAAM,CACnB,SACA,OAAQ,GAAS,OACjB,iBAAkB,GAAS,kBAAoB,EACjD,CAAC,CACH,CAEA,iBAAyB,EAAkB,EAA0B,CACnE,GAAI,EAAO,SAAW,EAAM,OAC1B,MAAO,GAGT,IAAM,EAAY,EAAO,IAAK,GAAM,EAAE,EAAE,CAAC,CAAC,KAAK,EACzC,EAAW,EAAM,IAAK,GAAM,EAAE,EAAE,CAAC,CAAC,KAAK,EAE7C,OAAO,EAAU,MAAM,EAAI,IAAU,IAAO,EAAS,EAAM,CAC7D,CAEA,2BAAmC,EAA2B,CACxD,KAAK,SAAS,eAChB,KAAK,aAAa,SAAU,CAC1B,OAAQ,EACR,iBAAkB,EACpB,CAAC,CAEL,CAEA,WACE,EACA,EACM,CACN,GAAI,CAAC,GAAc,EAAW,KAAK,IAAM,GACvC,OAEF,IAAM,EAAU,EAAW,MAAM,GAAG,CAAC,CAAC,OAAQ,GAAM,EAAE,KAAK,IAAM,EAAE,EACnE,IAAK,IAAM,KAAO,EAChB,EAAQ,UAAU,IAAI,EAAI,KAAK,CAAC,CAEpC,CAGA,cACE,EACA,EACM,CACN,GAAI,CAAC,GAAc,EAAW,KAAK,IAAM,GACvC,OAEF,IAAM,EAAU,EAAW,MAAM,GAAG,CAAC,CAAC,OAAQ,GAAM,EAAE,KAAK,IAAM,EAAE,EACnE,IAAK,IAAM,KAAO,EAChB,EAAQ,UAAU,OAAO,EAAI,KAAK,CAAC,CAEvC,CAGA,QAAsB,CAEpB,KAAK,cAAc,KAAK,KAAK,KAAM,KAAK,QAAQ,QAAQ,EACxD,KAAK,KAAK,KAAK,aAAa,gBAAiB,OAAO,EAGpD,KAAK,QAAQ,OAAO,MAAM,SAAW,EACvC,CAGA,SAAuB,CAErB,KAAK,WAAW,KAAK,KAAK,KAAM,KAAK,QAAQ,QAAQ,EACrD,KAAK,KAAK,KAAK,aAAa,gBAAiB,MAAM,EAGnD,KAAK,QAAQ,OAAO,MAAM,SAAW,EACvC,CAEA,MAAoB,CAClB,KAAK,KAAK,MAAM,KAAK,aAAa,IAAK,KAAK,QAAQ,SAAS,EAC7D,KAAK,KAAK,KAAK,aAAa,gBAAiB,MAAM,EAEnD,IAAM,EAAW,KAAK,iBAAiB,EAEvC,GAAI,CAAC,EAAU,CAEb,IAAM,EADU,KAAK,SAAS,eAAiB,KACpB,KAAK,QAAQ,SAAW,KAAK,QAAQ,SAChE,KAAK,WAAW,KAAK,KAAK,KAAM,CAAQ,EACxC,KAAK,WAAW,KAAK,QAAQ,KAAM,CAAQ,CAC7C,CAGA,KAAK,WAAW,KAAK,QAAQ,KAAM,KAAK,QAAQ,WAAW,EAG3D,KAAK,QAAQ,OAAO,MAAM,gBAAgB,aAAa,EAEnD,EACF,KAAK,UAAU,EAEf,KAAK,YAAY,EAInB,IAAM,EAAkB,KAAK,MAAM,mBAAmB,EACtD,GAAI,EAAgB,OAAQ,CAC1B,IAAM,EAAa,EAAgB,EAAgB,OAAS,EAAE,CAAC,GACzD,EAAiB,KAAK,QAAQ,KAAK,cACvC,aAAe,EAAa,IAC9B,EACI,GACF,KAAK,oBAAoB,KAAK,QAAQ,KAAM,CAAc,CAE9D,CACF,CAEA,mBAAoC,CAClC,OAAO,KAAK,qBAAuB,EACrC,CAEA,kBAAoC,CAalC,OAXE,KAAK,SAAS,YACd,KAAK,SAAS,QAAU,OACxB,CAAC,KAAK,cAEC,IAGL,KAAK,qBAAuB,OAC9B,KAAK,mBAAqB,EAAmB,KAAK,SAAS,KAAK,GAG3D,KAAK,mBACd,CAEA,qBAA6C,CAC3C,IAAM,EAAU,SAAS,cAAc,KAAK,EAC5C,KAAK,WAAW,EAAS,KAAK,QAAQ,YAAY,EAClD,KAAK,WAAW,EAAS,KAAK,QAAQ,IAAI,EAC1C,EAAQ,QAAQ,GAAK,KAAK,SAAS,GAEnC,IAAM,EAAS,SAAS,cAAc,KAAK,EAC3C,KAAK,WAAW,EAAQ,KAAK,QAAQ,WAAW,EAChD,EAAO,aAAa,OAAQ,QAAQ,EACpC,EAAO,aAAa,aAAc,MAAM,EAExC,IAAI,EAA+B,KAC/B,KAAK,SAAS,YAChB,EAAQ,SAAS,cAAc,KAAK,EACpC,KAAK,WAAW,EAAO,KAAK,QAAQ,UAAU,EAC9C,EAAM,GAAK,GAAG,KAAK,SAAS,GAAG,cAC/B,EAAM,YAAc,KAAK,SAAS,WAClC,EAAO,aAAa,kBAAmB,EAAM,EAAE,GAE/C,EAAO,aAAa,aAAc,KAAK,SAAS,SAAS,EAG3D,IAAM,EAAc,SAAS,cAAc,QAAQ,EACnD,EAAY,KAAO,SACnB,KAAK,WAAW,EAAa,KAAK,QAAQ,UAAU,EACpD,EAAY,aAAa,aAAc,OAAO,EAC9C,EAAY,QAAW,GAAa,CAClC,EAAE,gBAAgB,EAClB,KAAK,aAAa,OAAO,CAC3B,EAEA,IAAM,EAAW,SAAS,gBACxB,6BACA,KACF,EACA,EAAS,aAAa,UAAW,aAAa,EAC9C,IAAM,EAAY,SAAS,gBACzB,6BACA,MACF,EAgBA,OAfA,EAAU,aAAa,IAAK,KAAK,QAAQ,YAAY,EACrD,EAAS,YAAY,CAAS,EAC9B,EAAY,YAAY,CAAQ,EAEhC,EAAQ,QAAW,GAAa,CAC1B,EAAE,SAAW,GACf,KAAK,aAAa,OAAO,CAE7B,EAEI,GACF,EAAO,YAAY,CAAK,EAE1B,EAAQ,YAAY,CAAM,EAEnB,CAAE,UAAS,SAAQ,cAAa,OAAM,CAC/C,CAEA,WAA0B,CACnB,KAAK,gBAIV,KAAK,cAAc,OAAO,YAAY,KAAK,QAAQ,IAAI,EACvD,KAAK,WAAW,KAAK,QAAQ,KAAM,KAAK,QAAQ,YAAY,EAC5D,KAAK,QAAQ,KAAK,YAAY,KAAK,cAAc,WAAW,EAC5D,KAAK,QAAQ,KAAK,MAAM,IAAM,GAC9B,KAAK,QAAQ,KAAK,MAAM,KAAO,GAC/B,KAAK,QAAQ,KAAK,MAAM,OAAS,GACjC,KAAK,QAAQ,KAAK,MAAM,MAAQ,GAEhC,KAAK,cAAc,KAAK,cAAc,QAAS,KAAK,QAAQ,IAAI,EAChE,0BAA4B,CACrB,KAAK,eAGV,KAAK,WAAW,KAAK,cAAc,QAAS,KAAK,QAAQ,WAAW,CACtE,CAAC,EAED,KAAK,eAAe,EACtB,CAEA,gBAA+B,CACzB,AAMJ,KAAK,oBAFL,KAAK,kBAAoB,SAAS,KAAK,MAAM,SAC7C,SAAS,KAAK,MAAM,SAAW,SACP,GAC1B,CAEA,kBAAiC,CAC1B,KAAK,mBAIV,SAAS,KAAK,MAAM,SAAW,KAAK,kBACpC,KAAK,iBAAmB,GACxB,KAAK,kBAAoB,GAC3B,CAEA,yBAAwC,CAClC,KAAK,SAAS,iBAChB,KAAK,SAAS,gBAAgB,YAAY,KAAK,QAAQ,IAAI,EAGzD,KAAK,SAAS,kBAAoB,aACpC,KAAK,QAAQ,KAAK,MAAM,IAAM,UAC9B,KAAK,QAAQ,KAAK,MAAM,KAAO,UAC/B,KAAK,QAAQ,KAAK,MAAM,OAAS,IACjC,KAAK,QAAQ,KAAK,MAAM,MAAQ,OAEpC,CAGA,oBAAkC,CAC3B,KAAK,eAIN,KAAK,QAAQ,KAAK,gBAAkB,KAAK,cAAc,SAI3D,KAAK,WAAW,KAAK,cAAc,QAAS,KAAK,QAAQ,IAAI,EAC7D,KAAK,cAAc,KAAK,cAAc,QAAS,KAAK,QAAQ,WAAW,EACvE,KAAK,cAAc,KAAK,QAAQ,KAAM,KAAK,QAAQ,YAAY,EAC/D,KAAK,cAAc,YAAY,OAAO,EACtC,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACxB,CAGA,iBACE,EACA,EACe,CACf,IAAM,EAAU,EACd,KAAK,QAAQ,KACb,KAAK,SAAS,YAChB,EACA,OAAO,EACL,KAAK,QAAQ,KACb,EACA,EACA,CACF,CACF,CAEA,OAAqB,CACnB,KAAK,KAAK,KAAK,aAAa,gBAAiB,OAAO,EACpD,KAAK,KAAK,MAAM,KAAK,aAAa,IAAK,KAAK,QAAQ,UAAU,EAE9D,IAAM,EAAW,KAAK,qBAAuB,GAI7C,KAAK,cAAc,KAAK,QAAQ,KAAM,KAAK,QAAQ,WAAW,EAEzD,IACH,KAAK,cAAc,KAAK,KAAK,KAAM,KAAK,QAAQ,QAAQ,EACxD,KAAK,cAAc,KAAK,KAAK,KAAM,KAAK,QAAQ,QAAQ,GAGtD,GAAY,KAAK,eACnB,KAAK,cAAc,KAAK,cAAc,QAAS,KAAK,QAAQ,WAAW,EAGzE,KAAK,mBAAqB,KAG1B,KAAK,QAAQ,OAAO,MAAM,aAAa,cAAe,MAAM,EAG5D,KAAK,KAAK,KAAK,gBAAgB,uBAAuB,CACxD,CAGA,uBAAqC,CACnC,KAAK,cAAc,KAAK,KAAK,KAAM,KAAK,QAAQ,QAAQ,EACxD,KAAK,cAAc,KAAK,KAAK,KAAM,KAAK,QAAQ,QAAQ,EACxD,KAAK,cAAc,KAAK,QAAQ,KAAM,KAAK,QAAQ,QAAQ,EAC3D,KAAK,cAAc,KAAK,QAAQ,KAAM,KAAK,QAAQ,QAAQ,CAC7D,CAEA,mBAAiC,CAkB/B,GAhBA,KAAK,KAAK,KAAK,UAAY,GAC3B,KAAK,KAAK,KAAK,gBAAgB,OAAO,EACtC,KAAK,QAAQ,KAAK,UAAY,GAC9B,KAAK,QAAQ,KAAK,gBAAgB,OAAO,EAGzC,KAAK,WAAW,KAAK,KAAK,KAAM,KAAK,QAAQ,IAAI,EACjD,KAAK,WAAW,KAAK,QAAQ,KAAM,KAAK,QAAQ,OAAO,EAGnD,KAAK,SAAS,QAAU,KAC1B,KAAK,KAAK,KAAK,MAAM,QAAU,KAAK,SAAS,MAC7C,KAAK,QAAQ,KAAK,MAAM,QAAU,KAAK,SAAS,OAI9C,KAAK,SAAS,MAAM,WACjB,IAAM,KAAK,KAAK,SAAS,MACxB,EAAE,KAAK,IAAM,KACf,KAAK,KAAK,KAAK,UAAU,IAAI,EAAE,KAAK,CAAC,EACrC,KAAK,QAAQ,KAAK,UAAU,IAAI,EAAE,KAAK,CAAC,IAQ5C,KAAK,SAAS,kBAAoB,YAClC,KAAK,SAAS,kBAAoB,UAElC,KAAK,QAAQ,KAAK,UAAU,IAAI,MAAQ,KAAK,SAAS,eAAe,CAEzE,CAEA,sBAA8B,CAC5B,IAAM,EAAY,KAAK,QAAQ,KAAK,GAGpC,KAAK,KAAK,KAAK,KAAO,WACtB,KAAK,KAAK,KAAK,aAAa,gBAAiB,SAAS,EACtD,KAAK,KAAK,KAAK,aAAa,gBAAiB,CAAS,EACtD,KAAK,KAAK,KAAK,aAAa,gBAAiB,OAAO,EAEpD,KAAK,QAAQ,KAAK,aAAa,OAAQ,SAAS,EAChD,KAAK,QAAQ,KAAK,aAChB,aACA,KAAK,SAAS,UAAY,UAC5B,EAGI,KAAK,SAAS,YAChB,KAAK,QAAQ,KAAK,aAAa,uBAAwB,MAAM,EAI/D,KAAK,QAAQ,OAAO,MAAM,aAAa,gBAAiB,CAAS,CACnE,CAEA,SAAuB,CAErB,IAAM,EAAO,SAAS,cAAc,KAAK,EAGzC,EAAK,QAAQ,GAAK,KAAK,SAAS,GAIhC,EAAK,aAAa,aAAc,KAAK,SAAS,SAAS,EAGvD,EAAK,SAAW,EAKhB,EAAK,UAAa,GAA8B,CAE9C,OAAQ,EAAE,IAAV,CACE,IAAK,UACL,IAAK,YAGH,OAFA,KAAK,UAAU,KAAK,EACpB,EAAE,MAAQ,YAAc,KAAK,UAAU,MAAM,EAAI,KAAK,UAAU,IAAI,EAC7D,GACT,IAAK,MAEH,OADA,KAAK,aAAa,KAAK,EAChB,GACT,IAAK,QACL,IAAK,IACH,KAAK,UAAU,KAAK,EACpB,IAAM,EAAc,KAAK,QAAQ,KAAK,cACpC,IAAM,KAAK,QAAQ,SAAS,aAAa,CAC3C,EAIA,OAHI,GACF,EAAY,MAAM,EAEb,GACT,IAAK,SAEH,OADA,KAAK,aAAa,QAAQ,EACnB,EACX,CAOA,OAJI,EAAE,IAAI,SAAW,GACnB,KAAK,UAAU,KAAK,EAGf,EACT,EAGA,EAAK,QAAW,GAAmB,CAE7B,KAAK,SAAS,WAIlB,KAAK,SAAS,OACV,KAAK,aAAa,QAAQ,EAC1B,KAAK,UAAU,KAAK,EAC1B,EAGA,IAAM,EAAS,SAAS,cAAc,KAAK,EAC3C,KAAK,WAAW,EAAQ,KAAK,QAAQ,MAAM,EAC3C,EAAK,YAAY,CAAM,EAGvB,IAAM,EAAW,SAAS,cAAc,KAAK,EAC7C,KAAK,WAAW,EAAU,KAAK,QAAQ,QAAQ,EAC/C,EAAS,aAAa,OAAQ,QAAQ,EACtC,EAAS,aAAa,aAAc,KAAK,SAAS,YAAY,EAC9D,EAAS,aAAa,WAAY,GAAG,EAGrC,IAAM,EAAkB,KAAK,OAAO,mBAAmB,EAErD,CAAC,KAAK,SAAS,eACd,KAAK,SAAS,YACb,GACA,EAAgB,QAAU,GAC5B,KAAK,gBAAgB,EAErB,KAAK,WAAW,EAAU,KAAK,QAAQ,IAAI,EAE3C,KAAK,cAAc,EAAU,KAAK,QAAQ,IAAI,EAIhD,EAAS,QAAW,GAAa,CAQ/B,GAPA,EAAE,gBAAgB,EAGd,KAAK,SAAS,UAId,KAAK,SAAS,YAAc,KAAK,gBAAgB,EACnD,OAIF,IAAI,EAAe,GACb,EAAS,KAAK,MAAM,mBAAmB,EACzC,EAAQ,CAAC,EACT,EAAoC,GAExC,GAAI,KAAK,SAAS,WAAY,CAC5B,IAAM,EAAM,KAAK,SAAS,YACpB,EAAa,KAAK,MAAM,YAAY,EAE1C,GAAI,EAAM,GAAK,EAAW,OAAS,EACjC,EAAiB,KAAK,uBAAuB,EAC7C,EAAQ,EAAO,OAAQ,GAAM,EAAe,SAAS,EAAE,EAAE,CAAC,OACrD,GAAI,GAAO,EAChB,EAAiB,CAAC,OAElB,MAEJ,CAOA,GAJI,KAAK,UAAU,eACjB,EAAe,KAAK,UAAU,aAAa,EAAO,CAAM,IAAM,IAG5D,EAAc,CAChB,GAAI,KAAK,SAAS,WAChB,KAAK,UAAU,YAAY,EAAgB,EAAK,EAChD,KAAK,kBAAkB,MAClB,CAEL,IAAM,EAAc,KAAK,MAAM,eAAe,EACxC,EAAK,EAAc,EAAY,GAAK,GAE1C,KAAK,UAAU,YAAY,EAAI,EAAK,CACtC,CAGI,KAAK,SAAS,eAChB,KAAK,aAAa,WAAY,CAAE,iBAAkB,EAAK,CAAC,EAItD,KAAK,UAAU,aACjB,KAAK,UAAU,YAAY,KAAK,MAAM,mBAAmB,CAAC,CAE9D,CACF,EAEA,EAAS,UAAa,GAAqB,EACrC,EAAE,MAAQ,SAAW,EAAE,MAAQ,OACjC,EAAE,eAAe,EACjB,EAAS,MAAM,EAEnB,EAGA,IAAM,EAAc,SAAS,gBAC3B,6BACA,KACF,EACA,EAAY,aAAa,UAAW,aAAa,EACjD,IAAM,EAAe,SAAS,gBAC5B,6BACA,MACF,EACA,EAAa,aAAa,IAAK,KAAK,QAAQ,YAAY,EACxD,EAAY,YAAY,CAAY,EACpC,EAAS,YAAY,CAAW,EAChC,EAAK,YAAY,CAAQ,EAGzB,IAAM,EAAQ,SAAS,gBAAgB,6BAA8B,KAAK,EAC1E,KAAK,WAAW,EAAO,KAAK,QAAQ,KAAK,EACzC,EAAM,aAAa,UAAW,aAAa,EAC3C,IAAM,EAAY,SAAS,gBACzB,6BACA,MACF,EAQA,OAPA,EAAU,aAAa,IAAK,KAAK,QAAQ,UAAU,EAC/C,KAAK,SAAS,YAChB,KAAK,WAAW,EAAO,KAAK,QAAQ,IAAI,EAE1C,EAAM,YAAY,CAAS,EAC3B,EAAK,YAAY,CAAK,EAEf,CACC,OACE,SACR,SAAU,CACR,KAAM,EACN,IAAK,EACL,KAAM,CACR,EACA,MAAO,CACL,KAAM,EACN,KAAM,CACR,CACF,CACF,CAEA,UAAiB,EAAgC,CAK3C,IAAc,SAChB,KAAK,KAAK,KAAK,MAAM,CAAE,cAAe,EAAK,CAAC,CAEhD,CAEA,aAAqC,CAEnC,IAAM,EAAoB,KAAK,MAAM,OAClC,GAAM,EAAE,YACT,GACA,EACF,EAMI,EAAkB,KAAK,SAAS,gBAChC,EAAkB,SAChB,EAAkB,EAAE,CAAC,OAAS,GAEvB,EAAkB,EAAE,CAAC,OAAS,KACvC,EAAkB,EAAkB,EAAE,CAAC,MAFvC,EAAkB,EAAkB,EAAE,CAAC,MAO3C,IAAM,EAAc,SAAS,cAAc,KAAK,EAGhD,OAFA,KAAK,WAAW,EAAa,KAAK,QAAQ,WAAW,EACrD,EAAY,UAAY,EACjB,CACT,CAIA,cAA4B,CAE1B,GAAI,CAAC,KAAK,SAAS,WAAY,CAC7B,KAAK,kBAAkB,EACvB,MACF,CAEA,KAAK,qBAAqB,EAE1B,KAAK,kBAAkB,CACzB,CAEA,mBAAkC,CAChC,IAAM,EAAW,KAAK,MAAM,OAAQ,GAC3B,EAAE,UAAY,CAAC,EAAE,YACvB,GAAO,EAAK,EACT,EAAiB,EAAS,OAAS,EAAI,EAAS,GAAK,KAG3D,GAAI,CAAC,EACH,KAAK,KAAK,OAAO,UAAY,KAAK,YAAY,CAAC,CAAC,cAC3C,CAEL,IAAM,EAAc,SAAS,cAAc,KAAK,EAChD,KAAK,WAAW,EAAa,KAAK,QAAQ,MAAM,EAC5C,EAAe,KACjB,EAAY,UAAY,EAAe,KAEvC,EAAY,UAAY,EAAe,KAIzC,KAAK,KAAK,OAAO,UAAY,EAAY,SAC3C,CAGI,CAAC,KAAK,SAAS,eAAiB,CAAC,EAAS,OAC5C,KAAK,WAAW,KAAK,KAAK,SAAS,KAAM,KAAK,QAAQ,IAAI,EAE1D,KAAK,cAAc,KAAK,KAAK,SAAS,KAAM,KAAK,QAAQ,IAAI,CAEjE,CAEA,sBAAqC,CAEnC,IAAI,EAAe,KAAK,KAAK,OAAO,WAChC,EAAkB,KAAK,MAAM,OAAQ,GAEhC,EAAI,UAAY,EAAI,QAC1B,GAAO,EAAK,EAGf,GAAI,EAAgB,SAAW,EAAG,CAChC,KAAK,KAAK,OAAO,UAAY,KAAK,YAAY,CAAC,CAAC,UAChD,MACF,KAAO,CAEL,IAAM,EAAc,KAAK,KAAK,OAAO,cACnC,IAAM,KAAK,QAAQ,SAAS,aAAa,CAC3C,EACI,GACF,EAAY,OAAO,CAEvB,CAKA,GAAI,KAAK,SAAS,YAAa,CAC7B,IAAI,EAAe,EACf,KAAK,SAAS,YAChB,EAAe,KAAK,MAAM,qBAAqB,CAAY,GAG7D,IAAM,EAAa,SAAS,cAAc,KAAK,EAC/C,KAAK,WAAW,EAAY,KAAK,QAAQ,WAAW,EACpD,EAAW,YAAc,EACtB,IAAK,GAAc,EAAE,IAAI,CAAC,CAC1B,KAAK,IAAI,EAER,KAAK,SAAS,oBAChB,EAAW,aAAa,QAAS,EAAW,WAAW,EAGzD,KAAK,KAAK,OAAO,UAAY,EAAW,UACxC,MACF,CAGA,GAAI,EAAgB,OAAS,KAAK,SAAS,eAAgB,CAEzD,IAAM,EAAc,SAAS,cAAc,KAAK,EAChD,KAAK,WAAW,EAAa,KAAK,QAAQ,GAAG,EAC7C,EAAY,YAAc,KAAK,SAAS,iBAAiB,QACvD,WACA,EAAgB,OAAO,SAAS,CAClC,EAGA,KAAK,KAAK,OAAO,UAAY,EAAY,UACzC,MACF,KAAO,CAEL,IAAM,EAAmB,KAAK,KAAK,OAAO,cACxC,IAAM,KAAK,QAAQ,SAAS,KAAK,CACnC,EACI,GACF,EAAiB,OAAO,CAE5B,CAGI,KAAK,SAAS,YAChB,EAAkB,KAAK,MAAM,qBAAqB,CAAe,GAInE,IAAI,EAAgC,CAAC,EACrC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAa,OAAQ,IAAK,CAC5C,IAAM,EAAO,EAAa,GACpB,EAAK,EAAK,aAAa,SAAS,EAClC,IAEY,EAAgB,OAAQ,GAC7B,EAAI,KAAO,EACjB,EAGE,CAAA,CAAM,QACT,EAAY,KAAK,CAAI,EAG3B,CAEA,IAAM,EAAoB,EACxB,KAAK,QAAQ,KACb,KAAK,SAAS,YAChB,EAGA,IAAK,IAAM,KAAK,EACd,KAAK,WAAW,EAAG,KAAK,QAAQ,QAAQ,EACxC,EAAyB,EAAG,cAAe,CAAiB,CAAC,CAAC,SAAW,CACnE,KAAK,KAAK,OAAO,cAAc,GAAK,KAAK,KAAK,OAAO,SAAS,CAAC,GACjE,KAAK,KAAK,OAAO,YAAY,CAAC,CAElC,CAAC,EAIH,EAAe,KAAK,KAAK,OAAO,WAChC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAgB,OAAQ,IAAK,CAC/C,IAAI,EAAY,GAChB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAa,OAAQ,IACnC,EAAgB,EAAE,CAAC,KAAO,OAAO,EAAa,EAAE,CAAC,QAAQ,EAAE,IAC7D,EAAY,IAKZ,IAEE,KAAK,SAAS,WAIZ,EAAa,SAAW,EAH5B,KAAK,KAAK,OAAO,YAAY,KAAK,cAAc,EAAgB,EAAE,CAAC,EAKxD,IAAM,EACf,KAAK,KAAK,OAAO,aACf,KAAK,cAAc,EAAgB,EAAE,EACrC,EAAa,EACf,EAEA,EAAa,EAAI,EAAE,CAAC,sBAClB,WACA,KAAK,cAAc,EAAgB,EAAE,CACvC,EAIR,CAEA,KAAK,oCAAoC,CAC3C,CAEA,iBAAmC,CACjC,OACE,KAAK,SAAS,YACd,KAAK,SAAS,YAAc,GAC5B,KAAK,MAAM,mBAAmB,CAAC,CAAC,QAAU,KAAK,SAAS,WAE5D,CAEA,wBAA2C,CACzC,IAAI,EAAW,KAAK,MAAM,mBAAmB,EAK7C,OAJI,KAAK,SAAS,YAChB,EAAW,KAAK,MAAM,qBAAqB,CAAQ,GAG9C,EACJ,MAAM,EAAG,KAAK,SAAS,WAAW,CAAC,CACnC,IAAK,GAAW,EAAO,EAAE,CAC9B,CAEA,qCAAoD,CAClD,GAAI,CAAC,KAAK,SAAS,YAAc,KAAK,SAAS,YAC7C,OAGF,IAAM,EAAY,CAAC,KAAK,gBAAgB,EAClC,EAAgB,KAAK,KAAK,OAAO,iBACrC,IAAM,KAAK,QAAQ,SAAS,aAAa,CAC3C,EAEA,IAAK,IAAM,KAAgB,EACrB,EACF,KAAK,cAAc,EAA6B,KAAK,QAAQ,IAAI,EAEjE,KAAK,WAAW,EAA6B,KAAK,QAAQ,IAAI,CAGpE,CAEA,cAAqB,EAAgC,CACnD,IAAM,EAAQ,SAAS,cAAc,KAAK,EAC1C,KAAK,WAAW,EAAO,KAAK,QAAQ,KAAK,EACzC,EAAM,QAAQ,GAAK,EAAO,GAE1B,IAAM,EAAO,SAAS,cAAc,KAAK,EAMzC,GALA,KAAK,WAAW,EAAM,KAAK,QAAQ,SAAS,EAC5C,EAAK,YAAc,EAAO,KAC1B,EAAM,YAAY,CAAI,EAGlB,CAAC,EAAO,UAAW,CAErB,IAAM,EAAY,SAAS,cAAc,KAAK,EAC9C,KAAK,WAAW,EAAW,KAAK,QAAQ,WAAW,EACnD,EAAU,aAAa,WAAY,GAAG,EACtC,EAAU,aAAa,OAAQ,QAAQ,EACvC,EAAU,aACR,aACA,GAAG,KAAK,SAAS,WAAW,GAAG,EAAO,MACxC,EAEI,KAAK,gBAAgB,GACvB,KAAK,WAAW,EAAW,KAAK,QAAQ,IAAI,EAI9C,EAAU,QAAW,GAAa,CAKhC,GAJA,EAAE,eAAe,EACjB,EAAE,gBAAgB,EAGd,KAAK,SAAS,SAChB,OAIF,IAAI,EAAe,GACb,EAAS,KAAK,MAAM,mBAAmB,EACvC,EAAQ,EAAO,OAAQ,GACpB,EAAE,UAAY,EAAE,KAAO,EAAO,GACpC,EAAI,EAIL,UAAK,SAAS,aACd,EAAM,OAAS,KAAK,SAAS,eAM3B,KAAK,UAAU,eACjB,EAAe,KAAK,UAAU,aAAa,EAAO,CAAM,IAAM,IAG5D,GAAc,CAEhB,IAAI,EAAwB,CAAC,EAC7B,IAAK,IAAM,KAAK,EAAO,CACrB,GAAI,aAAa,MACV,IAAM,KAAK,EAAE,QACZ,EAAE,IACJ,EAAY,KAAK,EAAE,EAAE,EAKvB,aAAa,GACf,EAAY,KAAK,EAAE,EAAE,CAEzB,CACA,KAAK,UAAU,YAAY,EAAa,EAAK,EAGzC,KAAK,SAAS,eAChB,KAAK,aAAa,WAAY,CAAE,iBAAkB,EAAK,CAAC,EAItD,KAAK,UAAU,aACjB,KAAK,UAAU,YAAY,CAAK,EAGlC,KAAK,kBAAkB,EACvB,KAAK,oCAAoC,CAC3C,CACF,EAGA,IAAM,EAAY,SAAS,gBACzB,6BACA,KACF,EACA,EAAU,aAAa,UAAW,aAAa,EAC/C,IAAM,EAAa,SAAS,gBAC1B,6BACA,MACF,EACA,EAAW,aAAa,IAAK,KAAK,QAAQ,YAAY,EACtD,EAAU,YAAY,CAAU,EAChC,EAAU,YAAY,CAAS,EAE/B,EAAM,YAAY,CAAS,EAG3B,EAAU,UAAa,GAAM,CACvB,EAAE,MAAQ,SACZ,EAAU,MAAM,CAEpB,CACF,CAEA,OAAO,CACT,CAEA,YAA6B,CAC3B,IAAM,EAAO,SAAS,cAAc,KAAK,EAGzC,EAAK,QAAQ,GAAK,KAAK,SAAS,GAIhC,IAAM,EAAS,KAAK,UAAU,EAC9B,EAAK,YAAY,EAAO,IAAI,EAG5B,IAAM,EAAS,SAAS,cAAc,KAAK,EAC3C,KAAK,WAAW,EAAQ,KAAK,QAAQ,MAAM,EAC3C,EAAO,aAAa,YAAa,QAAQ,EACzC,EAAO,aAAa,cAAe,MAAM,EACzC,EAAO,aAAa,OAAQ,QAAQ,EACpC,EAAK,YAAY,CAAM,EAGvB,IAAM,EAAO,KAAK,QAAQ,EAG1B,OAFA,EAAK,YAAY,CAAI,EAEd,CACC,OACE,SACA,SACF,MACR,CACF,CAEA,SAAiB,EAAuB,CACjC,KAAK,SAAS,aAInB,KAAK,QAAQ,OAAO,YAAc,EACpC,CAEA,aAA2B,CACrB,SAAK,kBAAkB,EAI3B,IAAI,KAAK,SAAS,kBAAoB,WAAY,CAChD,KAAK,iBAAiB,EACtB,MACF,CAEA,GAAI,KAAK,SAAS,eAAiB,OAAQ,CACzC,KAAK,iBAAiB,EACtB,MACF,MAAO,GAAI,KAAK,SAAS,eAAiB,KAAM,CAC9C,KAAK,iBAAiB,EACtB,MACF,CAEI,KAAK,WAAW,IAAM,KACxB,KAAK,iBAAiB,EAEtB,KAAK,iBAAiB,CAbxB,CAeF,CAGA,uBAAqC,CAC/B,KAAK,SAAS,kBAAoB,YAAc,KAAK,kBAAkB,IAI3E,KAAK,qBAAqB,EAEtB,SAAO,eAAmB,OAI9B,KAAK,iBAAmB,IAAI,mBAAqB,CAC1C,KAAK,SAAS,SAInB,qBAAqB,KAAK,mBAAmB,EAC7C,KAAK,oBAAsB,0BAA4B,CACrD,KAAK,YAAY,CACnB,CAAC,EACH,CAAC,EAED,KAAK,uBAAuB,GAC9B,CAEA,sBAAoC,CAClC,qBAAqB,KAAK,mBAAmB,EAC7C,KAAK,kBAAkB,WAAW,EAClC,KAAK,iBAAmB,KACxB,KAAK,oBAAoB,CAC3B,CAEA,wBAAuC,CACrC,GAAI,CAAC,KAAK,iBACR,OAGF,IAAM,EAAW,IAAI,IACf,EAAW,GAA6B,CACxC,CAAC,GAAM,EAAS,IAAI,CAAE,IAI1B,EAAS,IAAI,CAAE,EACf,KAAK,iBAAkB,QAAQ,CAAE,EACnC,EAEA,EAAQ,KAAK,KAAK,IAAI,EAItB,IAAI,EAA6B,KAAK,KAAK,KAAK,cAC1C,EAAS,KAAK,SAAS,gBAE7B,IAAK,IAAI,EAAQ,EAAG,GAAU,EAAQ,IACpC,EAAQ,CAAM,EACV,IAAW,GAFwB,IAKvC,EAAS,EAAO,aAEpB,CAEA,WAA2B,CACzB,IAAM,EAAO,SAAS,cAAc,KAAK,EACnC,EAAQ,SAAS,cAAc,OAAO,EACtC,EAAU,SAAS,cAAc,KAAK,EAC5C,KAAK,WAAW,EAAM,KAAK,QAAQ,MAAM,EAGzC,IAAM,EAAuB,CAC3B,OACA,OACF,EA+DA,GA5DK,KAAK,SAAS,aACjB,KAAK,WAAW,EAAM,KAAK,QAAQ,IAAI,EACvC,EAAM,SAAW,IAGnB,EAAM,KAAO,SACb,EAAM,YAAc,KAAK,SAAS,kBAClC,EAAM,SAAW,GACjB,EAAM,aAAa,aAAc,KAAK,SAAS,iBAAiB,EAChE,EAAM,aAAa,oBAAqB,MAAM,EAC9C,EAAM,aAAa,iBAAkB,KAAK,EAC1C,EAAM,aAAa,eAAgB,KAAK,EACxC,EAAM,aAAa,cAAe,KAAK,EAEvC,EAAM,aAAa,cAAe,MAAM,EAExC,EAAM,QAAU,EAAU,GAAa,CACrC,KAAK,UAAU,OAAQ,EAAE,OAA4B,KAAK,CAC5D,EAAG,GAAG,EAGN,EAAM,UAAa,GAA8B,CAE/C,OAAQ,EAAE,IAAV,CACE,IAAK,UACL,IAAK,YAEH,OADA,EAAE,MAAQ,YAAc,KAAK,UAAU,MAAM,EAAI,KAAK,UAAU,IAAI,EAC7D,GACT,IAAK,MAKH,OADA,KAAK,aAAa,KAAK,EAChB,GACT,IAAK,SAEH,OADA,KAAK,aAAa,QAAQ,EACnB,GACT,IAAK,QAEH,IAAM,EAAmB,KAAK,QAAQ,KAAK,cACzC,IAAM,KAAK,QAAQ,SAAS,aAAa,CAC3C,EAUA,OATI,GAEF,EAAiB,MAAM,EAChB,IACE,KAAK,UAAU,SAExB,EAAQ,MAAM,EACP,IAEF,EACX,CAEA,MAAO,EACT,EAEA,EAAK,YAAY,CAAK,EAGlB,KAAK,UAAU,QAAS,CAE1B,KAAK,WAAW,EAAS,KAAK,QAAQ,OAAO,EAG7C,IAAM,EAAO,SAAS,gBAAgB,6BAA8B,KAAK,EACzE,EAAK,aAAa,UAAW,aAAa,EAC1C,IAAM,EAAW,SAAS,gBACxB,6BACA,MACF,EACA,EAAS,aAAa,IAAK,KAAK,QAAQ,WAAW,EACnD,EAAK,YAAY,CAAQ,EACzB,EAAQ,YAAY,CAAI,EAGxB,EAAQ,QAAW,GAAa,CAK9B,GAJA,EAAE,eAAe,EACjB,EAAE,gBAAgB,EAGd,CAAC,KAAK,UAAU,QAClB,OAIF,IAAM,EAAa,KAAK,QAAQ,OAAO,MAAM,MAAM,KAAK,EACxD,GAAI,IAAe,GAAI,CACrB,KAAK,QAAQ,OAAO,MAAM,MAAM,EAChC,MACF,CAKA,IAAM,EAAa,GAAwB,CACzC,IAAI,EAAY,IAAI,EAAO,CAAE,EAM7B,GAHA,KAAK,UAAU,UAAU,CAAS,EAG9B,KAAK,SAAS,WAAY,CAC5B,IAAI,EAAM,KAAK,MAAM,YAAY,EACjC,EAAI,KAAK,EAAU,EAAE,EACrB,KAAK,UAAU,YAAY,EAAK,EAAI,CACtC,MACE,KAAK,UAAU,YAAY,CAAC,EAAU,EAAE,EAAG,EAAI,EAOjD,GAHA,KAAK,UAAU,OAAO,EAAE,EAGpB,KAAK,SAAS,cAAe,CAC/B,IAAM,EAAoB,EAAqB,KAAK,QAAQ,IAAI,EAChE,eAAiB,CACf,KAAK,aAAa,SAAU,CAAE,iBAAkB,EAAK,CAAC,CACxD,EAAG,CAAiB,CACtB,CACF,EAGM,EAAe,KAAK,UAAU,QAAQ,CAAU,EAIpD,IAAiB,IACjB,GACiB,OAMf,aAAwB,QAC1B,EAAa,KAAM,GAAU,CACvB,OAAO,GAAU,SACnB,EAAU,CACR,KAAM,EACC,OACT,CAAC,EACQ,aAAwB,MACjC,KAAK,YAAY,EAAa,OAAO,EAErC,EAAU,CAAK,CAEnB,CAAC,EACQ,OAAO,GAAiB,SACjC,EAAU,CACR,KAAM,EACN,MAAO,CACT,CAAC,EACQ,aAAwB,MACjC,KAAK,YAAY,EAAa,OAAO,EAErC,EAAU,CAAY,EAI1B,EACA,EAAK,YAAY,CAAO,EAGxB,EAAa,QAAU,CACrB,KAAM,EACN,IAAK,EACL,KAAM,CACR,CACF,CAEA,OAAO,CACT,CAEA,aAA2B,CACzB,KAAK,QAAQ,OAAO,MAAM,MAAM,CAAE,cAAe,EAAK,CAAC,CACzD,CAEA,WACE,EAAiB,GACjB,EAAc,GACd,EAAY,GACM,CAElB,IAAI,EAAQ,IAAM,KAAK,QAAQ,SAAS,QAAQ,EAWhD,OAVI,IACF,GAAS,SAAW,KAAK,QAAQ,SAAS,aAAa,EAAI,KAEzD,IACF,GAAS,SAAW,KAAK,QAAQ,SAAS,UAAU,EAAI,KAEtD,IACF,GAAS,SAAW,KAAK,QAAQ,SAAS,MAAM,EAAI,KAG/C,MAAM,KAAK,KAAK,QAAQ,KAAK,iBAAiB,CAAK,CAAC,CAC7D,CAGA,UAAiB,EAA0B,CAEzC,IAAM,EAAU,KAAK,WAAW,GAAM,GAAM,EAAI,EAGhD,GAAI,EAAQ,SAAW,EACrB,OAIF,GAAI,EAAQ,SAAW,GAGnB,CAAC,EAAQ,EAAE,CAAC,UAAU,SAAS,KAAK,QAAQ,SAAS,aAAa,CAAC,EACnE,CACA,KAAK,WAAW,EAAQ,GAAI,KAAK,QAAQ,WAAW,EACpD,MACF,CAIF,IAAI,EAAc,GAClB,IAAK,IAAM,KAAK,EACV,EAAE,UAAU,SAAS,KAAK,QAAQ,SAAS,aAAa,CAAC,IAC3D,EAAc,IAKlB,GAAI,CAAC,OACE,IAAM,KAAK,EACd,GAAI,EAAE,UAAU,SAAS,KAAK,QAAQ,SAAS,UAAU,CAAC,EAAG,CAC3D,KAAK,WAAW,EAAG,KAAK,QAAQ,WAAW,EAC3C,KACF,EAKJ,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,OAAQ,IAElC,GAAI,EAAQ,EAAE,CAAC,UAAU,SAAS,KAAK,QAAQ,SAAS,aAAa,CAAC,EAAG,CACvE,IAAM,EAAa,EAAQ,GAE3B,KAAK,cAAc,EAAY,KAAK,QAAQ,WAAW,EAGvD,IAAM,EAAa,EAAW,cAC9B,GACE,GACA,EAAW,UAAU,SAAS,KAAK,QAAQ,SAAS,UAAU,CAAC,EAC/D,CACA,IAAM,EAAgB,EAAW,cAC/B,IAAM,KAAK,QAAQ,SAAS,eAAe,CAC7C,EACI,GACF,EAAc,MAAM,CAExB,CAGA,IAAI,EACF,EACE,IAAQ,OACJ,EAAI,EAAI,EAAQ,OACd,EAAI,EACJ,EACF,EAAI,GAAK,EACP,EAAI,EACJ,EAAQ,OAAS,GAE3B,KAAK,WAAW,EAAc,KAAK,QAAQ,WAAW,EACtD,KAAK,oBAAoB,KAAK,QAAQ,KAAM,CAAY,EAGpD,EAAa,IACf,KAAK,KAAK,KAAK,aAAa,wBAAyB,EAAa,EAAE,EAItE,IAAM,EAAe,EAAa,cAClC,GACE,GACA,EAAa,UAAU,SAAS,KAAK,QAAQ,SAAS,OAAO,CAAC,EAC9D,CACA,IAAM,EAAgB,EAAa,cACjC,IAAM,KAAK,QAAQ,SAAS,eAAe,CAC7C,EACI,GACF,EAAc,MAAM,CAExB,CAEA,MACF,CAKF,IAAM,EAAiB,EAAQ,IAAQ,OAAS,EAAI,EAAQ,OAAS,GACrE,KAAK,WAAW,EAAgB,KAAK,QAAQ,WAAW,EAGpD,EAAe,IACjB,KAAK,KAAK,KAAK,aAAa,wBAAyB,EAAe,EAAE,EAIxE,KAAK,oBAAoB,KAAK,QAAQ,KAAM,CAAc,CAC5D,CAGA,SAAiC,CAC/B,IAAM,EAAU,SAAS,cAAc,KAAK,EAC5C,KAAK,WAAW,EAAS,KAAK,QAAQ,IAAI,EAG1C,IAAM,EAAS,KAAK,SAAS,GAAK,QAIlC,MAHA,GAAQ,GAAK,EACb,EAAQ,QAAQ,GAAK,EAEd,CACT,CAEA,YAAmB,EAAe,CAChC,KAAK,sBAAwB,GAE7B,KAAK,QAAQ,KAAK,UAAY,GAE9B,IAAM,EAAW,SAAS,cAAc,KAAK,EAC7C,KAAK,WAAW,EAAU,KAAK,QAAQ,KAAK,EAC5C,EAAS,YAAc,EACvB,KAAK,QAAQ,KAAK,YAAY,CAAQ,CACxC,CAEA,iBAAyB,CACvB,KAAK,sBAAwB,GAE7B,KAAK,QAAQ,KAAK,UAAY,GAE9B,IAAM,EAAe,SAAS,cAAc,KAAK,EACjD,KAAK,WAAW,EAAc,KAAK,QAAQ,SAAS,EACpD,EAAa,YAAc,KAAK,SAAS,cACzC,KAAK,QAAQ,KAAK,YAAY,CAAY,EAC1C,KAAK,SAAS,KAAK,SAAS,aAAa,CAC3C,CAGA,cAAqB,EAAmC,CAYtD,GAXA,KAAK,qBAAuB,GAC5B,KAAK,oBAAsB,EACxB,IAAK,GACJ,aAAa,EAAS,CAAC,CAAC,EAAI,EAAE,QAAQ,IAAK,GAAO,IAAI,EAAO,CAAE,CAAC,CAClE,CAAC,CACA,KAAK,EAGR,KAAK,QAAQ,KAAK,UAAY,GAG1B,EAAK,SAAW,EAAG,CACrB,KAAK,sBAAwB,GAC7B,IAAM,EAAY,SAAS,cAAc,KAAK,EAI9C,GAHA,KAAK,WAAW,EAAW,KAAK,QAAQ,MAAM,EAG1C,KAAK,UAAU,QAAS,CAC1B,IAAM,EAAiB,KAAK,SAAS,YAAY,QAC/C,UACA,KAAK,QAAQ,OAAO,MAAM,KAC5B,EACA,EAAU,UAAY,EACtB,KAAK,SAAS,CAAc,CAC9B,KACE,GAAU,UAAY,KAAK,SAAS,WACpC,KAAK,SAAS,KAAK,SAAS,UAAU,EAExC,KAAK,QAAQ,KAAK,YAAY,CAAS,EACvC,MACF,CAGI,KAAK,SAAS,eAAiB,CAAC,KAAK,SAAS,aAEtB,KAAK,MAAM,OAClC,GAAM,EAAE,YACT,GACA,EAEG,CAAA,CAAkB,QACrB,KAAK,MAAM,UACT,IAAI,EAAO,CACT,KAAM,GACN,MAAO,GACP,SAAU,GACV,YAAa,EACf,CAAC,EACD,EACF,GAKJ,IAAM,EAAW,SAAS,uBAAuB,EACjD,IAAK,IAAM,KAAK,EAAM,CAEpB,GAAI,aAAa,EAAU,CAEzB,IAAM,EAAa,SAAS,cAAc,KAAK,EAC/C,KAAK,WAAW,EAAY,KAAK,QAAQ,QAAQ,EAGjD,IAAM,EAAgB,SAAS,cAAc,KAAK,EAClD,KAAK,WAAW,EAAe,KAAK,QAAQ,aAAa,EACzD,EAAW,YAAY,CAAa,EAGpC,IAAM,EAAoB,SAAS,cAAc,KAAK,EACtD,KAAK,WAAW,EAAmB,KAAK,QAAQ,iBAAiB,EACjE,EAAkB,YAAc,EAAE,MAClC,EAAc,YAAY,CAAiB,EAG3C,IAAM,EAAkB,SAAS,cAAc,KAAK,EAKpD,GAJA,KAAK,WAAW,EAAiB,KAAK,QAAQ,eAAe,EAC7D,EAAc,YAAY,CAAe,EAGrC,KAAK,SAAS,YAAc,EAAE,UAAW,CAE3C,IAAM,EAAY,SAAS,cAAc,KAAK,EAC9C,KAAK,WAAW,EAAW,KAAK,QAAQ,iBAAiB,EAGzD,IAAM,EAAc,KAAK,sBAAsB,EAAE,OAAmB,EAGhE,GACF,KAAK,WAAW,EAAW,KAAK,QAAQ,QAAQ,EAIlD,IAAM,EAAiB,SAAS,cAAc,MAAM,EACpD,EAAe,YAAc,KAAK,uBAAuB,CAAW,EACpE,EAAU,YAAY,CAAc,EAGpC,IAAM,EAAe,SAAS,gBAC5B,6BACA,KACF,EACA,EAAa,aAAa,UAAW,aAAa,EAClD,EAAU,YAAY,CAAY,EAGlC,IAAM,EAAe,SAAS,gBAC5B,6BACA,MACF,EACA,EAAa,aAAa,IAAK,KAAK,QAAQ,oBAAoB,EAChE,EAAa,YAAY,CAAY,EAGrC,IAAM,EAAiB,SAAS,gBAC9B,6BACA,MACF,EACA,EAAe,aAAa,IAAK,KAAK,QAAQ,sBAAsB,EACpE,EAAa,YAAY,CAAc,EAGvC,EAAU,iBAAiB,QAAU,GAAkB,CACrD,EAAE,eAAe,EACjB,EAAE,gBAAgB,EAGlB,IAAM,EAAkB,KAAK,MAAM,YAAY,EAO/C,GANuB,KAAK,sBAC1B,EAAE,QACF,IAAI,IAAI,CAAe,CAIrB,EAAgB,CAElB,IAAM,EAAc,EAAgB,OAAQ,GAAM,CAChD,IAAK,IAAM,KAAK,EAAE,QAChB,GAAI,IAAM,EAAE,GACV,MAAO,GAIX,MAAO,EACT,CAAC,EAED,KAAK,UAAU,YAAY,EAAa,EAAI,EAC5C,MACF,KAAO,CAEL,IAAI,EAAY,EAAE,QACf,IAAK,GAAM,EAAE,EAAE,CAAC,CAChB,OAAQ,GAAO,IAAO,IAAA,EAAS,EAC5B,EAAc,EAAgB,OAAO,CAAS,EAIpD,IAAK,IAAM,KAAK,EAAE,QACZ,EAAE,IAAM,CAAC,KAAK,MAAM,cAAc,EAAE,EAAE,GACxC,KAAK,UAAU,UAAU,IAAI,EAAO,CAAC,CAAC,EAI1C,KAAK,UAAU,YAAY,EAAa,EAAI,EAC5C,MACF,CACF,CAAC,EAGD,EAAgB,YAAY,CAAS,CACvC,CAGA,GAAI,EAAE,WAAa,MAAO,CAExB,IAAM,EAAmB,SAAS,cAAc,KAAK,EACrD,KAAK,WAAW,EAAkB,KAAK,QAAQ,gBAAgB,EAG/D,IAAM,EAAsB,SAAS,gBACnC,6BACA,KACF,EACA,EAAoB,aAAa,UAAW,aAAa,EACzD,KAAK,WAAW,EAAqB,KAAK,QAAQ,KAAK,EACvD,EAAiB,YAAY,CAAmB,EAGhD,IAAM,EAAwB,SAAS,gBACrC,6BACA,MACF,EACA,EAAoB,YAAY,CAAqB,EAInD,EAAE,QAAQ,KAAM,GAAM,EAAE,QAAQ,GAChC,KAAK,QAAQ,OAAO,MAAM,MAAM,KAAK,IAAM,IAE3C,KAAK,WAAW,EAAkB,KAAK,QAAQ,QAAQ,EACvD,EAAsB,aAAa,IAAK,KAAK,QAAQ,SAAS,GACrD,EAAE,WAAa,QACxB,KAAK,WAAW,EAAY,KAAK,QAAQ,QAAQ,EACjD,EAAsB,aAAa,IAAK,KAAK,QAAQ,SAAS,GACrD,EAAE,WAAa,UACxB,KAAK,WAAW,EAAY,KAAK,QAAQ,KAAK,EAC9C,EAAsB,aAAa,IAAK,KAAK,QAAQ,UAAU,GAIjE,EAAc,iBAAiB,QAAU,GAAkB,CACzD,EAAE,eAAe,EACjB,EAAE,gBAAgB,EAEH,KAAK,uBAClB,EACA,CAGG,GAOH,KAAK,cAAc,EAAY,KAAK,QAAQ,QAAQ,EACpD,KAAK,cAAc,EAAkB,KAAK,QAAQ,QAAQ,EAC1D,KAAK,WAAW,EAAY,KAAK,QAAQ,KAAK,EAC9C,EAAsB,aAAa,IAAK,KAAK,QAAQ,UAAU,IAT/D,KAAK,4BAA4B,CAAU,EAC3C,KAAK,cAAc,EAAY,KAAK,QAAQ,KAAK,EACjD,KAAK,cAAc,EAAkB,KAAK,QAAQ,QAAQ,EAC1D,KAAK,WAAW,EAAY,KAAK,QAAQ,QAAQ,EACjD,EAAsB,aAAa,IAAK,KAAK,QAAQ,SAAS,EAOlE,CAAC,EAGD,EAAgB,YAAY,CAAgB,CAC9C,CAGA,EAAW,YAAY,CAAa,EAGpC,IAAK,IAAM,KAAU,EAAE,QACrB,EAAW,YAAY,KAAK,OAAO,IAAI,EAAO,CAAM,CAAC,CAAC,EACtD,EAAS,YAAY,CAAU,CAEnC,CAGI,aAAa,GACf,EAAS,YAAY,KAAK,OAAO,CAAW,CAAC,CAEjD,CAGA,KAAK,QAAQ,KAAK,YAAY,CAAQ,EACtC,KAAK,uBAAuB,CAAI,EAChC,KAAK,SACH,KAAK,SAAS,YAAY,QACxB,UACA,OAAO,KAAK,oBAAoB,MAAM,CACxC,CACF,CACF,CAGA,yBAA0C,CAKxC,OAJK,KAAK,sBAKR,KAAK,QAAQ,KAAK,cAChB,IAAM,KAAK,QAAQ,SAAS,QAAQ,CACtC,IAAM,KANC,EAQX,CAEA,wBAAsC,CACpC,KAAK,qBAAuB,EAC9B,CAGA,qBACE,EACA,EACM,CACN,IAAM,EAAa,EAAO,KAAK,EAC/B,GAAI,IAAe,KAAK,qBACtB,OAEF,KAAK,qBAAuB,EAE5B,IAAM,EAA2B,CAAC,EAC5B,EAAY,KAAK,QAAQ,KAAK,iBAClC,IAAM,KAAK,QAAQ,SAAS,QAAQ,CACtC,EAEA,IAAK,IAAM,KAAY,EAAW,CAChC,IAAM,EAAK,EAAS,QAAQ,GAC5B,GAAI,CAAC,EACH,SAGF,IAAM,EAAc,KAAK,MAAM,cAAc,CAAE,EAC/C,GAAI,CAAC,EACH,SAGF,IAAM,EACJ,EAAY,aACZ,CAAC,EAAY,SACZ,EAAY,UAAY,KAAK,SAAS,aAEnC,EAAgB,EAAa,EAAa,CAAU,EAEtD,GAAuB,CAAC,GAC1B,KAAK,WAAW,EAAU,KAAK,QAAQ,IAAI,EAC3C,KAAK,cAAc,EAAU,KAAK,QAAQ,WAAW,IAErD,KAAK,cAAc,EAAU,KAAK,QAAQ,IAAI,EAC9C,KAAK,wBAAwB,EAAU,EAAa,CAAU,EAC9D,EAAe,KAAK,CAAW,GAG7B,EAAY,UACd,KAAK,WAAW,EAAU,KAAK,QAAQ,QAAQ,EAC/C,EAAS,aAAa,gBAAiB,MAAM,IAE7C,KAAK,cAAc,EAAU,KAAK,QAAQ,QAAQ,EAClD,EAAS,aAAa,gBAAiB,OAAO,EAElD,CAEA,KAAK,oBAAsB,EAC3B,KAAK,oCAAoC,CAAU,EAE/C,EAAe,SAAW,EAC5B,KAAK,2BAA2B,EAAG,CAAU,GAE7C,KAAK,wBAAwB,EAC7B,KAAK,SACH,KAAK,SAAS,YAAY,QACxB,UACA,OAAO,EAAe,MAAM,CAC9B,CACF,GAGF,KAAK,8BAA8B,CACrC,CAEA,uBAA+B,EAAmC,CAChE,IAAM,EAAe,KAAK,MAAM,eAAe,EAAK,EAC9C,EAAkB,EACrB,IAAK,GACJ,aAAa,EAAS,CAAC,CAAC,EAAI,EAAE,QAAQ,IAAK,GAAO,IAAI,EAAO,CAAE,CAAC,CAClE,CAAC,CACA,KAAK,EAER,GAAI,EAAgB,SAAW,EAAa,OAAQ,CAClD,KAAK,sBAAwB,GAC7B,MACF,CAEA,IAAM,EAAW,IAAI,IAAI,EAAa,IAAK,GAAM,EAAE,EAAE,CAAC,EACtD,KAAK,sBAAwB,EAAgB,MAAO,GAClD,EAAS,IAAI,EAAE,EAAE,CACnB,CACF,CAEA,uBACE,EACA,EACS,CAKT,OAJI,EAAW,UAAU,SAAS,KAAK,QAAQ,SAAS,OAAO,CAAC,EACvD,GAIP,EAAW,UAAU,SAAS,KAAK,QAAQ,SAAS,UAAU,CAAC,GAC/D,EAAiB,UAAU,SAAS,KAAK,QAAQ,SAAS,UAAU,CAAC,CAEzE,CAEA,sBAA8B,EAA+B,CAC3D,IAAM,EAAW,EAAW,cAC1B,IAAM,KAAK,QAAQ,SAAS,kBAAkB,CAChD,EAKA,GAJI,CAAC,GAID,EAAW,UAAU,SAAS,KAAK,QAAQ,SAAS,OAAO,CAAC,EAC9D,OAGF,KAAK,cAAc,EAAY,KAAK,QAAQ,QAAQ,EACpD,KAAK,cAAc,EAAU,KAAK,QAAQ,QAAQ,EAClD,KAAK,WAAW,EAAY,KAAK,QAAQ,KAAK,EAE9C,IAAM,EAAQ,EAAS,cAAc,MAAM,EACvC,GACF,EAAM,aAAa,IAAK,KAAK,QAAQ,UAAU,CAEnD,CAEA,4BAAoC,EAAqC,CACvE,IAAM,EAAY,KAAK,QAAQ,KAAK,iBAClC,IAAM,KAAK,QAAQ,SAAS,UAAU,CACxC,EAEA,IAAK,IAAM,KAAc,EACnB,IAAe,GAInB,KAAK,sBAAsB,CAAyB,CAExD,CAEA,oCAA4C,EAA0B,CACpE,IAAM,EAAY,KAAK,QAAQ,KAAK,iBAClC,IAAM,KAAK,QAAQ,SAAS,UAAU,CACxC,EAEA,IAAK,IAAM,KAAc,EAAW,CAClC,IAAM,EAAY,EAAW,iBAC3B,IAAM,KAAK,QAAQ,SAAS,QAAQ,CACtC,EAEI,EAAmB,GACvB,IAAK,IAAM,KAAY,EACrB,GAAI,CAAC,EAAS,UAAU,SAAS,KAAK,QAAQ,SAAS,MAAM,CAAC,EAAG,CAC/D,EAAmB,GACnB,KACF,CAGF,GAAI,CAAC,EAAkB,CACrB,KAAK,WAAW,EAA8B,KAAK,QAAQ,IAAI,EAC/D,QACF,CAEA,KAAK,cAAc,EAA8B,KAAK,QAAQ,IAAI,EAE9D,IAAe,KACjB,KAAK,cAAc,EAA8B,KAAK,QAAQ,KAAK,EACnE,KAAK,WAAW,EAA8B,KAAK,QAAQ,QAAQ,EAEvE,CACF,CAEA,2BACE,EACA,EACM,CAGN,GAFA,KAAK,wBAAwB,EAEzB,EAAe,EACjB,OAGF,IAAM,EAAY,SAAS,cAAc,KAAK,EAG9C,GAFA,KAAK,WAAW,EAAW,KAAK,QAAQ,MAAM,EAE1C,KAAK,UAAU,QAAS,CAC1B,IAAM,EAAiB,KAAK,SAAS,YAAY,QAC/C,UACA,CACF,EACA,EAAU,UAAY,EACtB,KAAK,SAAS,CAAc,CAC9B,KACE,GAAU,UAAY,KAAK,SAAS,WACpC,KAAK,SAAS,KAAK,SAAS,UAAU,EAGxC,KAAK,QAAQ,KAAK,YAAY,CAAS,CACzC,CAEA,yBAAwC,CAItC,KAHsB,QAAQ,KAAK,iBACjC,IAAM,KAAK,QAAQ,SAAS,QAAQ,CAEtC,CAAA,CAAS,QAAS,GAAY,EAAQ,OAAO,CAAC,CAChD,CAEA,wBACE,EACA,EACA,EACM,CACN,IAAM,EAAa,EAAO,KAAK,EAC3B,KAAK,SAAS,iBAAmB,IAAe,GAClD,EAAS,UAAY,KAAK,cACxB,EAAO,OAAS,GAAmB,EAAO,KAArB,EAAO,KAC5B,EACA,KAAK,QAAQ,iBACf,EACS,EAAO,OAAS,GAGzB,EAAS,YAAc,EAAO,KAF9B,EAAS,UAAY,EAAO,KAK1B,KAAK,SAAS,oBAAsB,EAAS,YAC/C,EAAS,aAAa,QAAS,EAAS,WAAW,EAEnD,EAAS,gBAAgB,OAAO,CAEpC,CAGA,oBAAqC,CACnC,OACE,KAAK,QAAQ,KAAK,cAChB,IAAM,KAAK,QAAQ,SAAS,QAAQ,CACtC,IAAM,IAEV,CAGA,iCAAkD,CAKhD,OAJI,KAAK,QAAQ,OAAO,MAAM,MAAM,KAAK,IAAM,IAIxC,KAAK,mBAAmB,CACjC,CAGA,uBAAqC,CACnC,IAAM,EAAc,IAAI,IAAI,KAAK,MAAM,YAAY,CAAC,EAC9C,EAAY,KAAK,QAAQ,KAAK,iBAClC,IAAM,KAAK,QAAQ,SAAS,QAAQ,CACtC,EAEI,EAAwC,KAE5C,IAAK,IAAM,KAAY,EAAW,CAChC,IAAM,EAAK,EAAS,QAAQ,GAC5B,GAAI,CAAC,EACH,SAGF,IAAM,EAAc,KAAK,MAAM,cAAc,CAAE,EAC/C,GAAI,CAAC,EACH,SAGF,IAAM,EAAa,EAAY,IAAI,CAAE,EAEjC,GACF,KAAK,WAAW,EAAU,KAAK,QAAQ,QAAQ,EAC/C,EAAS,aAAa,gBAAiB,MAAM,EAC7C,EAAiB,IAEjB,KAAK,cAAc,EAAU,KAAK,QAAQ,QAAQ,EAClD,EAAS,aAAa,gBAAiB,OAAO,GAG5C,KAAK,SAAS,eACZ,EACF,KAAK,WAAW,EAAU,KAAK,QAAQ,IAAI,GAE3C,KAAK,cAAc,EAAU,KAAK,QAAQ,IAAI,EACzC,EAAY,SACf,KAAK,WAAW,EAAU,KAAK,QAAQ,IAAI,GAInD,CAEI,CAAC,KAAK,SAAS,YAAc,EAC/B,KAAK,KAAK,KAAK,aAAa,wBAAyB,EAAe,EAAE,EAC7D,CAAC,KAAK,SAAS,YAAc,EAAY,OAAS,GAC3D,KAAK,KAAK,KAAK,gBAAgB,uBAAuB,EAGxD,KAAK,8BAA8B,CACrC,CAEA,+BAA8C,CAC5C,GAAI,CAAC,KAAK,SAAS,WACjB,OAGF,IAAM,EAAc,IAAI,IAAI,KAAK,MAAM,YAAY,CAAC,EAC9C,EAAY,KAAK,QAAQ,KAAK,iBAClC,IAAM,KAAK,QAAQ,SAAS,UAAU,CACxC,EAEA,IAAK,IAAM,KAAc,EAAW,CAClC,IAAM,EAAY,EAAW,cAC3B,IAAM,KAAK,QAAQ,SAAS,mBAAmB,CACjD,EAEA,GAAI,CAAC,EACH,SAGF,IAAM,EAAY,EAAW,iBAC3B,IAAM,KAAK,QAAQ,SAAS,QAAQ,CACtC,EAEI,EAAc,EAAU,OAAS,EACrC,IAAK,IAAM,KAAY,EAAW,CAChC,IAAM,EAAK,EAAS,QAAQ,GAC5B,GAAI,CAAC,GAAM,CAAC,EAAY,IAAI,CAAE,EAAG,CAC/B,EAAc,GACd,KACF,CACF,CAEI,EACF,KAAK,WAAW,EAAW,KAAK,QAAQ,QAAQ,EAEhD,KAAK,cAAc,EAAW,KAAK,QAAQ,QAAQ,EAGrD,IAAM,EAAiB,EAAU,cAAc,MAAM,EACjD,IACF,EAAe,YAAc,KAAK,uBAAuB,CAAW,EAExE,CACF,CAEA,uBAA+B,EAA8B,CAC3D,OAAO,EAAc,eAAiB,YACxC,CAEA,sBACE,EACA,EACS,CACT,GAAI,EAAQ,SAAW,EACrB,MAAO,GAGT,IAAK,IAAM,KAAU,EAKnB,GAAI,EAJe,EACP,EAAO,IAAM,EAAY,IAAI,EAAO,EAAE,EAC9C,EAAO,UAGT,MAAO,GAIX,MAAO,EACT,CAGA,OAAc,EAAgC,CAE5C,GAAI,EAAO,YAAa,CACtB,IAAM,EAAc,SAAS,cAAc,KAAK,EAGhD,OAFA,KAAK,WAAW,EAAa,KAAK,QAAQ,MAAM,EAChD,KAAK,WAAW,EAAa,KAAK,QAAQ,IAAI,EACvC,CACT,CAGA,IAAM,EAAW,SAAS,cAAc,KAAK,EA+N7C,MA9NA,GAAS,QAAQ,GAAK,EAAO,GAC7B,EAAS,GAAK,KAAK,SAAS,GAAK,IAAM,EAAO,GAC9C,KAAK,WAAW,EAAU,KAAK,QAAQ,MAAM,EAC7C,EAAS,aAAa,OAAQ,QAAQ,EAClC,EAAO,OACT,EAAO,MAAM,MAAM,GAAG,CAAC,CAAC,QAAS,GAAsB,CACrD,EAAS,UAAU,IAAI,CAAS,CAClC,CAAC,EAEC,EAAO,QACT,EAAS,MAAM,QAAU,EAAO,OAIlC,KAAK,wBACH,EACA,EACA,KAAK,QAAQ,OAAO,MAAM,KAC5B,EAGK,EAAO,SACV,KAAK,WAAW,EAAU,KAAK,QAAQ,IAAI,EAIzC,EAAO,UACT,KAAK,WAAW,EAAU,KAAK,QAAQ,QAAQ,EAI7C,EAAO,UAAY,KAAK,SAAS,cACnC,KAAK,WAAW,EAAU,KAAK,QAAQ,IAAI,EAIzC,EAAO,UACT,KAAK,WAAW,EAAU,KAAK,QAAQ,QAAQ,EAC/C,EAAS,aAAa,gBAAiB,MAAM,EAC7C,KAAK,KAAK,KAAK,aAAa,wBAAyB,EAAS,EAAE,IAEhE,KAAK,cAAc,EAAU,KAAK,QAAQ,QAAQ,EAClD,EAAS,aAAa,gBAAiB,OAAO,GAIhD,EAAS,iBAAiB,QAAU,GAAkB,CACpD,EAAE,eAAe,EACjB,EAAE,gBAAgB,EAGlB,IAAM,EAAkB,KAAK,MAAM,YAAY,EACzC,EAAU,EAAE,cACZ,EAAY,OAAO,EAAQ,QAAQ,EAAE,EACrC,EAAc,KAAK,MAAM,cAAc,CAAS,GAAK,EACrD,EAAsB,EAAgB,SAAS,CAAS,EACxD,EAAQ,EAAE,SAAW,EAAE,QAG7B,GAAI,EAAO,SACT,OAKF,GACE,CAAC,KAAK,SAAS,YACf,GACA,CAAC,KAAK,SAAS,cACf,CACA,KAAK,2BAA2B,CAAW,EAC3C,MACF,CAGA,GAAI,GAAuB,EAAY,UAAW,CAChD,KAAK,2BAA2B,CAAW,EAC3C,MACF,CAIA,GACG,KAAK,SAAS,YACb,KAAK,SAAS,aAAe,EAAgB,QAC7C,CAAC,GACF,KAAK,SAAS,YACb,KAAK,SAAS,aAAe,EAAgB,QAC7C,GACA,CAAC,EAEH,OAIF,IAAI,EAAe,GACb,EAAS,KAAK,MAAM,mBAAmB,EACzC,EAAQ,CAAC,EAGb,GAAI,KAAK,SAAS,WAAY,CAC5B,IAAM,EAAsB,EAAO,KAChC,GAAc,EAAE,KAAO,CAC1B,EAIA,GAHgB,EAAE,UAGH,KAAK,mBAAoB,CACtC,IAAM,EAAU,KAAK,oBACf,EAAY,EAAQ,UACvB,GAAc,EAAE,KAAO,KAAK,mBAAoB,EACnD,EACM,EAAe,EAAQ,UAC1B,GAAc,EAAE,KAAO,EAAO,EACjC,EAEA,GAAI,GAAa,GAAK,GAAgB,EAAG,CACvC,IAAM,EAAa,KAAK,IAAI,EAAW,CAAY,EAC7C,EAAW,KAAK,IAAI,EAAW,CAAY,EAI3C,EAHe,EAAQ,MAAM,EAAY,EAAW,CAGpC,CAAA,CAAa,OAChC,GAAQ,CAAC,EAAO,KAAM,GAAM,EAAE,KAAO,EAAI,EAAE,CAC9C,EACA,AAQE,EAPA,EAAO,OAAS,EAAc,QAC9B,KAAK,SAAS,YAGN,EAAO,OAAO,CAAa,EAG3B,CAEZ,KACE,GAAQ,CAEZ,KAGE,CAKE,EALE,EAEM,EAAO,OAAQ,GAAc,EAAE,KAAO,CAAS,EAG/C,EAAO,OAAO,CAAW,EAEnC,KAAK,mBAAqB,CAa9B,CA2BA,GAxBK,KAAK,SAAS,aACjB,AAKE,EALE,EAEM,CAAC,EAGD,CAAC,CAAW,GAKnB,KAAK,UAAU,eAClB,EAAe,IAGb,KAAK,UAAU,eAEjB,AAGE,EAHE,KAAK,UAAU,aAAa,EAAO,CAAM,IAAM,IAOjD,EAAc,CAGX,KAAK,MAAM,cAAc,CAAS,GACrC,KAAK,UAAU,UAAU,CAAM,EAIjC,KAAK,UAAU,YACb,EAAM,IAAK,GAAc,EAAE,EAAE,EAC7B,EACF,EAIA,IAAM,EAAgB,EAAE,SAAW,EAAE,SAAW,EAAE,SAEhD,KAAK,SAAS,eACd,EAAE,KAAK,SAAS,YAAc,IAG9B,KAAK,aAAa,SAAU,CAC1B,OAAQ,EACR,iBAAkB,KAAK,iBAAiB,EAAQ,CAAK,CACvD,CAAC,EAIC,KAAK,UAAU,aACjB,KAAK,UAAU,YAAY,CAAK,CAEpC,CACF,CAAC,EAEM,CACT,CAEA,SAAuB,CACrB,KAAK,qBAAqB,EAEtB,KAAK,eACP,KAAK,iBAAiB,EAClB,KAAK,QAAQ,KAAK,gBAAkB,KAAK,cAAc,QACzD,KAAK,wBAAwB,EAE/B,KAAK,cAAc,QAAQ,OAAO,EAClC,KAAK,cAAgB,MACZ,KAAK,kBACd,KAAK,iBAAiB,EAIxB,KAAK,KAAK,KAAK,OAAO,EAGtB,KAAK,QAAQ,KAAK,OAAO,EAEzB,KAAK,0BAA0B,CACjC,CAGA,2BAA0C,CACxC,IAAM,EAAK,KAAK,SAAS,GACnB,EAAY,KAAK,QAAQ,SAAS,MAAM,EACxC,EAAe,KAAK,QAAQ,SAAS,SAAS,EAC9C,EAAa,KAAK,QAAQ,SAAS,cAAc,EAEvD,SAAS,iBAA8B,aAAa,EAAG,GAAG,CAAC,CAAC,QAAS,GAAO,EAExE,EAAG,UAAU,SAAS,CAAS,GAC/B,EAAG,UAAU,SAAS,CAAY,GAClC,EAAG,UAAU,SAAS,CAAU,IAEhC,EAAG,OAAO,CAEd,CAAC,CACH,CAEA,cAAsB,EAAa,EAAa,EAAmB,CACjE,IAAM,EAAa,EAAO,KAAK,EAC/B,GAAI,IAAe,GACjB,OAAO,EAIT,IAAM,EAAgB,EAAW,QAAQ,sBAAuB,MAAM,EAGhE,EAAU,SAAS,cAAc,KAAK,EAC5C,EAAQ,UAAY,EAGpB,IAAM,EAAsB,GAAe,CACzC,GAAI,EAAK,WAAa,KAAK,UAAW,CACpC,IAAM,EAAO,EAAK,aAAe,GAC3B,EAAY,OAAO,IAAM,EAAgB,IAAK,GAAG,EAEvD,GAAI,EAAM,KAAK,CAAI,EAAG,CAEpB,IAAM,EAAU,SAAS,cAAc,MAAM,EAG7C,EAFmB,MAAM,CAEzB,CAAA,CAAM,SAAS,EAAM,IAAU,CAC7B,GAAI,GAAQ,EAAM,KAAK,CAAI,EAAG,CAE5B,IAAM,EAAO,SAAS,cAAc,MAAM,EAC1C,EAAK,UAAY,EACjB,EAAK,YAAc,EACnB,EAAQ,YAAY,CAAI,CAC1B,MAAW,GAET,EAAQ,YAAY,SAAS,eAAe,CAAI,CAAC,CAErD,CAAC,EAGD,EAAK,YAAY,aAAa,EAAS,CAAI,CAC7C,CACF,MAAW,EAAK,WAAa,KAAK,cAEhC,MAAM,KAAK,EAAK,UAAU,CAAC,CAAC,QAAS,GACnC,EAAmB,CAAK,CAC1B,CAEJ,EAKA,OAFA,MAAM,KAAK,EAAQ,UAAU,CAAC,CAAC,QAAS,GAAS,EAAmB,CAAI,CAAC,EAElE,EAAQ,SACjB,CAEA,oBAA4B,EAAoC,CAC9D,IAAM,EAAU,IAAc,QACxB,EAAW,EAAU,KAAK,QAAQ,SAAW,KAAK,QAAQ,SAC1D,EAAc,EAAU,KAAK,QAAQ,SAAW,KAAK,QAAQ,SAOnE,GALA,KAAK,cAAc,KAAK,KAAK,KAAM,CAAW,EAC9C,KAAK,WAAW,KAAK,KAAK,KAAM,CAAQ,EACxC,KAAK,cAAc,KAAK,QAAQ,KAAM,CAAW,EACjD,KAAK,WAAW,KAAK,QAAQ,KAAM,CAAQ,EAEvC,EAAS,CACX,IAAM,EAAa,KAAK,KAAK,KAAK,aAC5B,EAAgB,KAAK,QAAQ,KAAK,aACxC,KAAK,QAAQ,KAAK,MAAM,OACtB,KAAO,EAAa,EAAgB,GAAK,gBAC7C,KACE,MAAK,QAAQ,KAAK,MAAM,OAAS,kBAErC,CAEA,oBAAmC,CACjC,IAAM,EAAgB,KAAK,KAAK,KAAK,sBAAsB,EAE3D,GAAI,KAAK,SAAS,kBAAoB,WAAY,CAChD,KAAK,kBAAkB,CAAa,EACpC,MACF,CAEA,KAAK,oBAAoB,EAEzB,IAAI,EACA,EAEA,KAAK,SAAS,kBAAoB,SACpC,EAAM,EAAc,IAAM,EAAc,OACxC,EAAO,EAAc,OAErB,EAAM,EAAc,IAAM,OAAO,QAAU,EAAc,OACzD,EAAO,EAAc,KAAO,OAAO,SAGrC,KAAK,QAAQ,KAAK,MAAM,IAAM,EAAM,KACpC,KAAK,QAAQ,KAAK,MAAM,KAAO,EAAO,KAEtC,KAAK,kBAAkB,CAAa,EAEpC,IAAM,EAAa,KAAK,qBAAqB,CAAa,EAC1D,GAAI,IAAe,KAAM,CACvB,KAAK,QAAQ,KAAK,MAAM,KACtB,KAAK,sBAAsB,EAAM,EAAc,KAAM,CAAU,EAAI,KACrE,MACF,CAGA,KAAK,iBAAmB,0BAA4B,CAClD,KAAK,iBAAmB,EACxB,KAAK,8BAA8B,CACrC,CAAC,CACH,CAEA,kBAA0B,EAA8B,CACtD,IAAM,EAAK,KAAK,SAAS,aAKzB,GAJA,KAAK,QAAQ,KAAK,MAAM,MAAQ,GAChC,KAAK,QAAQ,KAAK,MAAM,SAAW,GACnC,KAAK,QAAQ,KAAK,MAAM,SAAW,GAE/B,CAAC,EAAI,CACH,KAAK,SAAS,kBAAoB,aACpC,KAAK,QAAQ,KAAK,MAAM,MAAQ,EAAc,MAAQ,MAExD,MACF,CAEI,EAAG,WAAW,GAAG,EACnB,KAAK,QAAQ,KAAK,MAAM,SAAW,EAAG,MAAM,CAAC,EACpC,EAAG,WAAW,GAAG,EAC1B,KAAK,QAAQ,KAAK,MAAM,SAAW,EAAG,MAAM,CAAC,EAE7C,KAAK,QAAQ,KAAK,MAAM,MAAQ,CAEpC,CAEA,qBAAoC,CAClC,AAEE,KAAK,oBADL,qBAAqB,KAAK,gBAAgB,EAClB,EAE5B,CAGA,qBAA6B,EAAuC,CAClE,IAAM,EAAK,KAAK,SAAS,aACzB,GAAI,CAAC,EACH,OAAO,EAAc,MAEvB,GAAI,EAAG,WAAW,GAAG,GAAK,EAAG,WAAW,GAAG,GAAK,EAAG,SAAS,GAAG,EAC7D,OAAO,KAGT,IAAM,EAAK,WAAW,CAAE,EACxB,OAAO,OAAO,MAAM,CAAE,EAAI,KAAO,CACnC,CAEA,sBACE,EACA,EACA,EACQ,CACR,IACM,EAAe,EAAe,EACpC,GAAI,GAAgB,OAAO,WACzB,OAAO,EAIT,IAAM,EAAU,GADC,GAAgB,OAAO,WAAa,KAMrD,OAHI,KAAK,SAAS,kBAAoB,QAC7B,KAAK,IAAI,EAAG,CAAO,EAErB,KAAK,IAAI,OAAO,QAAS,CAAO,CACzC,CAEA,+BAA8C,CAE5C,IAAM,EADc,KAAK,QAAQ,KAAK,sBACjB,CAAA,CAAY,MACjC,GAAI,GAAgB,OAAO,WACzB,OAIF,IAAM,EAAW,GAAgB,OAAO,WAAa,IAE/C,GADc,WAAW,KAAK,QAAQ,KAAK,MAAM,IAAI,GAAK,GAClC,EAE1B,KAAK,SAAS,kBAAoB,QACpC,KAAK,QAAQ,KAAK,MAAM,KAAO,KAAK,IAAI,EAAG,CAAO,EAAI,KAEtD,KAAK,QAAQ,KAAK,MAAM,KAAO,KAAK,IAAI,OAAO,QAAS,CAAO,EAAI,IAEvE,CAEA,kBAAgC,CAC9B,KAAK,oBAAoB,OAAO,EAChC,KAAK,mBAAmB,CAC1B,CAEA,kBAAgC,CAC9B,KAAK,oBAAoB,OAAO,EAChC,KAAK,mBAAmB,CAC1B,CAEA,oBACE,EACA,EACM,CACN,IAAM,EAAO,EAAU,UAAY,EAAU,UACvC,EAAU,EAAO,EAAU,aAC3B,EAAO,EAAQ,UACf,EAAU,EAAO,EAAQ,aAE3B,EAAO,EACT,EAAU,WAAa,EAAO,EACrB,EAAU,IACnB,EAAU,WAAa,EAAU,EAErC,CAEA,YAAmC,CACjC,IAAM,EAAa,KAAK,KAAK,KAAK,aAC5B,EAAW,KAAK,KAAK,KAAK,sBAAsB,EAChD,EAAgB,KAAK,QAAQ,KAAK,aAUxC,OATmB,OAAO,aAAe,EAAS,IAAM,IAEtC,GACZ,EAAS,IAAM,EACV,KAEF,MAIX,CAGA,mBAAiC,CAC/B,GAAI,CAAC,KAAK,OAAS,CAAC,KAAK,SACvB,OAEF,IAAM,EAAW,KAAK,MAAM,mBAAmB,EACzC,EAAmB,GAAY,EAAS,OAAS,EACjD,EAAa,KAAK,SAAS,WAC3B,EAAgB,KAAK,SAAS,cAC9B,EAAgB,KAAK,gBAAgB,EAErC,EAAiB,KAAK,KAAK,SAAS,KACpC,EAAY,KAAK,QAAQ,KAG7B,GACA,EAAE,GAAc,CAAC,IACjB,CAAC,EAED,KAAK,cAAc,EAAgB,CAAS,EAE5C,KAAK,WAAW,EAAgB,CAAS,CAE7C,CACF,ECttFA,SAAgB,EACd,EACA,EACe,CACf,IAAM,EAAuB,CAC3B,aAAc,GACd,gBAAiB,GACjB,sBAAuB,GACvB,iBAAkB,EACpB,EAEA,IAAK,IAAM,KAAK,EAAW,CAEzB,GAAI,EAAE,SAAW,IACX,EAAE,gBAAkB,aACtB,EAAM,gBAAkB,IAGtB,EAAE,gBAAkB,UACtB,EAAM,aAAe,IAGnB,EAAE,OAAS,aAAa,CAI1B,IAAK,IAAM,KAAK,MAAM,KAAK,EAAE,UAAU,EACrC,GACE,EAAE,WAAa,UACd,EAAwB,QAAU,EAAO,MAC1C,CACA,EAAM,iBAAmB,GACzB,KACF,CAIF,EAAM,sBAAwB,EAChC,EAKE,EAAE,OAAO,WAAa,YAAc,EAAE,OAAO,WAAa,YAC5D,EAAM,sBAAwB,GAElC,CAEA,OAAO,CACT,CCxEA,IAAqB,EAArB,KAA4B,CAC1B,OAGA,cACA,cACA,iBACA,gBACA,aAGA,OAA0B,GAC1B,SAA4C,KAC5C,WAA8B,GAC9B,qBAA6D,KAG7D,oBAA2D,KAC3D,6BAAoE,KACpE,yBAAgE,KAChE,wBAA+D,KAE/D,YAAY,EAA2B,CACrC,KAAK,OAAS,EAEd,KAAK,YAAc,KAAK,YAAY,KAAK,IAAI,EAE7C,KAAK,OAAO,iBAAiB,SAAU,KAAK,YAAa,CAEvD,QAAS,EACX,CAAC,EAGD,KAAK,SAAW,IAAI,iBAAiB,KAAK,YAAY,KAAK,IAAI,CAAC,EAGhE,KAAK,aAAa,EAAI,CACxB,CAEA,QAAsB,CACpB,KAAK,OAAO,SAAW,EACzB,CAEA,SAAuB,CACrB,KAAK,OAAO,SAAW,EACzB,CAEA,QAAsB,CACpB,KAAK,OAAO,SAAW,GAGvB,KAAK,OAAO,MAAM,SAAW,WAC7B,KAAK,OAAO,MAAM,MAAQ,MAC1B,KAAK,OAAO,MAAM,OAAS,MAC3B,KAAK,OAAO,MAAM,QAAU,IAC5B,KAAK,OAAO,MAAM,SAAW,SAC7B,KAAK,OAAO,MAAM,cAAgB,OAElC,KAAK,OAAO,MAAM,OAAS,IAC3B,KAAK,OAAO,MAAM,QAAU,IAC5B,KAAK,OAAO,MAAM,YAAc,IAEhC,KAAK,OAAO,MAAM,SAAW,aAMzB,SAAS,gBAAkB,KAAK,QAClC,KAAK,OAAO,aAAa,cAAe,MAAM,EAO3C,KAAK,sBACR,KAAK,oBAAuB,GAAa,CACvC,EAAE,eAAe,EACjB,EAAE,gBAAgB,EAClB,EAAE,yBAAyB,CAC7B,EAEA,KAAK,6BAAgC,GAAa,CAChD,EAAE,eAAe,EACjB,EAAE,gBAAgB,EAClB,EAAE,yBAAyB,CAC7B,EAEA,KAAK,yBAA4B,GAAa,CAM5C,KAAK,OAAO,gBAAgB,aAAa,EACzC,EAAE,eAAe,EACjB,EAAE,gBAAgB,EAClB,EAAE,yBAAyB,CAC7B,EAGA,KAAK,4BAAgC,CACnC,KAAK,OAAO,aAAa,cAAe,MAAM,CAChD,EAGA,KAAK,OAAO,iBAAiB,QAAS,KAAK,oBAAqB,CAC9D,QAAS,GACT,QAAS,EACX,CAAC,EACD,KAAK,OAAO,iBACV,YACA,KAAK,6BACL,CAAE,QAAS,GAAM,QAAS,EAAM,CAClC,EACA,KAAK,OAAO,iBAAiB,QAAS,KAAK,yBAA0B,CACnE,QAAS,GACT,QAAS,EACX,CAAC,EACD,KAAK,OAAO,iBAAiB,OAAQ,KAAK,wBAAyB,CACjE,QAAS,GACT,QAAS,EACX,CAAC,EAEL,CAEA,QAAsB,CACpB,KAAK,OAAO,gBAAgB,UAAU,EAEtC,KAAK,OAAO,MAAM,SAAW,GAC7B,KAAK,OAAO,MAAM,MAAQ,GAC1B,KAAK,OAAO,MAAM,OAAS,GAC3B,KAAK,OAAO,MAAM,QAAU,GAC5B,KAAK,OAAO,MAAM,SAAW,GAC7B,KAAK,OAAO,MAAM,cAAgB,GAClC,KAAK,OAAO,MAAM,OAAS,GAC3B,KAAK,OAAO,MAAM,QAAU,GAC5B,KAAK,OAAO,MAAM,YAAc,GAChC,KAAK,OAAO,MAAM,SAAW,GAC7B,KAAK,OAAO,gBAAgB,aAAa,EAGzC,AAIE,KAAK,uBAHL,KAAK,OAAO,oBAAoB,QAAS,KAAK,oBAAqB,CACjE,QAAS,EACX,CAAC,EAC0B,MAE7B,AAME,KAAK,gCALL,KAAK,OAAO,oBACV,YACA,KAAK,6BACL,CAAE,QAAS,EAAK,CAClB,EACoC,MAEtC,AAIE,KAAK,4BAHL,KAAK,OAAO,oBAAoB,QAAS,KAAK,yBAA0B,CACtE,QAAS,EACX,CAAC,EAC+B,MAElC,AAIE,KAAK,2BAHL,KAAK,OAAO,oBAAoB,OAAQ,KAAK,wBAAyB,CACpE,QAAS,EACX,CAAC,EAC8B,KAEnC,CAEA,aAAoB,EAAiB,CACnC,KAAK,OAAS,EAGV,GACE,KAAK,UACP,KAAK,SAAS,QAAQ,KAAK,OAAQ,CACjC,QAAS,GACT,UAAW,GACX,WAAY,EACd,CAAC,EAKA,GACC,KAAK,UACP,KAAK,SAAS,WAAW,CAG/B,CAIA,YAAmB,EAAoB,CAMrC,OALI,KAAK,QAAU,KAAK,eACtB,KAAK,cAAc,KAAK,mBAAmB,CAAC,EAIvC,EACT,CAEA,YAAoB,EAAmC,CAErD,GAAI,CAAC,KAAK,OACR,OAIF,GAAM,CACJ,eACA,kBACA,wBACA,iBAAkB,GAChB,EAAkB,EAAW,KAAK,MAAM,EACxC,EAAmB,EAevB,GAZI,GAAgB,KAAK,eACvB,KAAK,cAAc,KAAK,OAAO,UAAU,MAAM,GAAG,CAAC,EAIjD,GAAmB,KAAK,mBAC1B,KAAK,aAAa,EAAK,EACvB,KAAK,iBAAiB,KAAK,OAAO,QAAQ,EAC1C,KAAK,aAAa,EAAI,GAIpB,GAAyB,KAAK,gBAAiB,CAEjD,GAAI,KAAK,WAAY,CAGnB,GAAI,KAAK,OAAO,QAAQ,OAAS,EAAG,CAClC,IAAM,EAAc,KAAK,QAAQ,EAE7B,EAAY,OAAS,IACvB,KAAK,qBAAuB,EAEhC,CACI,GACF,KAAK,OAAO,cAAc,IAAI,MAAM,QAAQ,CAAC,EAE/C,MACF,CAEA,KAAK,aAAa,EAAK,EACvB,KAAK,gBAAgB,KAAK,QAAQ,CAAC,EACnC,KAAK,aAAa,EAAI,EAGtB,EAAmB,EACrB,CAEI,GACF,KAAK,OAAO,cAAc,IAAI,MAAM,QAAQ,CAAC,CAEjD,CAGA,SAAwC,CACtC,IAAI,EAAO,CAAC,EAGN,EAAQ,KAAK,OAAO,WAG1B,IAAK,IAAM,KAAK,EAEV,EAAE,WAAa,YACjB,EAAK,KAAK,KAAK,oBAAoB,CAAwB,CAAC,EAI1D,EAAE,WAAa,UACjB,EAAK,KAAK,KAAK,kBAAkB,CAAsB,CAAC,EAI5D,OAAO,CACT,CAEA,oBAA2B,EAAyC,CAClE,IAAI,EAAO,CACT,GAAI,EAAS,GACb,MAAO,EAAS,MAChB,UAAW,EAAS,QAChB,EAAS,QAAQ,YAAc,OAC/B,GACJ,SAAU,EAAS,QAAU,EAAS,QAAQ,SAAW,MACzD,QAAS,CAAC,CACZ,EAEM,EAAU,EAAS,WACzB,IAAK,IAAM,KAAK,EACV,EAAE,WAAa,UACjB,EAAK,QAAS,KAAK,KAAK,kBAAkB,CAAsB,CAAC,EAIrE,OAAO,CACT,CAGA,kBAAyB,EAAmC,CAC1D,MAAO,CACL,GAAI,EAAO,GACX,MAAO,EAAO,MACd,KAAM,EAAO,KACb,KAAM,EAAO,SAAW,EAAO,QAAQ,KAAO,EAAO,QAAQ,KAAO,GACpE,gBAAiB,EAAO,gBACxB,SAAU,EAAO,SACjB,QAAS,EAAO,MAAM,UAAY,OAClC,SAAU,EAAO,SACjB,UAAW,EAAO,QAAU,EAAO,QAAQ,YAAc,OAAS,GAClE,YAAa,EAAO,QAAQ,cAAgB,OAC5C,MAAO,EAAO,UACd,MAAO,EAAO,MAAM,QACpB,KAAM,EAAe,EAAO,OAAO,CACrC,CACF,CAEA,oBAAsC,CACpC,IAAI,EAAU,CAAC,EAGT,EAAO,KAAK,OAAO,WAIzB,IAAK,IAAM,KAAK,EAAM,CACpB,GAAI,EAAE,WAAa,WAAY,CAC7B,IAAM,EAAkB,EAAE,WAC1B,IAAK,IAAM,KAAM,EACf,GAAI,EAAG,WAAa,SAAU,CAC5B,IAAM,EAAS,EACX,EAAO,UACT,EAAQ,KAAK,KAAK,kBAAkB,CAAM,CAAC,CAE/C,CAEJ,CAEA,GAAI,EAAE,WAAa,SAAU,CAC3B,IAAM,EAAS,EACX,EAAO,UACT,EAAQ,KAAK,KAAK,kBAAkB,CAAM,CAAC,CAE/C,CACF,CAEA,OAAO,CACT,CAEA,mBAAqC,CACnC,OAAO,KAAK,mBAAmB,CAAC,CAAC,IAAK,GAAW,EAAO,KAAK,CAC/D,CAGA,gBAAuB,EAA2B,CAChD,GAAI,EAAO,SAAW,EACpB,MAAO,GAGT,IAAM,EAAe,IAAI,IACvB,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC,CAAC,IAAK,GAAW,EAAO,KAAK,CAC9D,EACA,OAAO,EAAO,MAAO,GAAU,EAAa,IAAI,CAAK,CAAC,CACxD,CAEA,YAAmB,EAAqB,CAEtC,KAAK,aAAa,EAAK,EAGvB,IAAM,EAAU,KAAK,OAAO,WAI5B,IAAK,IAAM,KAAK,EAAS,CACvB,GAAI,EAAE,WAAa,WAAY,CAE7B,IAAM,EACJ,EAAS,WACX,IAAK,IAAM,KAAM,EACf,GAAI,EAAG,WAAa,SAAU,CAC5B,IAAM,EAAS,EACf,EAAO,SAAW,EAAI,SAAS,EAAO,EAAE,CAC1C,CAEJ,CAEA,GAAI,EAAE,WAAa,SAAU,CAC3B,IAAM,EAAS,EACf,EAAO,SAAW,EAAI,SAAS,EAAO,EAAE,CAC1C,CACF,CAGA,IAAM,EAAW,KAAK,mBAAmB,EACpC,KAAK,OAAO,WACf,KAAK,OAAO,MAAQ,EAAS,SAAW,EAAI,EAAS,EAAE,CAAC,MAAQ,IAIlE,KAAK,OAAO,cAAc,IAAI,MAAM,SAAU,CAAE,QAAS,EAAK,CAAC,CAAC,EAEhE,KAAK,aAAa,EAAI,CACxB,CAOA,mBAA0B,EAAwB,CAEhD,KAAK,aAAa,EAAK,EAGvB,IAAM,EAAU,KAAK,OAAO,WAI5B,IAAK,IAAM,KAAK,EAAS,CACvB,GAAI,EAAE,WAAa,WAAY,CAE7B,IAAM,EACJ,EAAS,WACX,IAAK,IAAM,KAAM,EACf,GAAI,EAAG,WAAa,SAAU,CAC5B,IAAM,EAAS,EACf,EAAO,SAAW,EAAO,SAAS,EAAO,KAAK,CAChD,CAEJ,CAEA,GAAI,EAAE,WAAa,SAAU,CAC3B,IAAM,EAAS,EACf,EAAO,SAAW,EAAO,SAAS,EAAO,KAAK,CAChD,CACF,CAEA,IAAM,EAAW,KAAK,mBAAmB,EACpC,KAAK,OAAO,WAEf,KAAK,OAAO,MAAQ,EAAS,SAAW,EAAI,EAAS,EAAE,CAAC,MAAQ,IAIlE,KAAK,OAAO,cAAc,IAAI,MAAM,SAAU,CAAE,QAAS,EAAK,CAAC,CAAC,EAEhE,KAAK,aAAa,EAAI,CACxB,CAEA,aAAoB,EAAa,EAAgB,EAA0B,CAEzE,KAAK,aAAa,EAAK,EAGnB,IACF,KAAK,OAAO,QAAQ,GAAK,GAIvB,IACF,KAAK,OAAO,MAAM,QAAU,GAI1B,IACF,KAAK,OAAO,UAAY,GACxB,EAAQ,QAAS,GAAM,CACjB,EAAE,KAAK,IAAM,IACf,KAAK,OAAO,UAAU,IAAI,EAAE,KAAK,CAAC,CAEtC,CAAC,GAIH,KAAK,aAAa,EAAI,CACxB,CAEA,cAAqB,EAAmC,CAEtD,GAAI,CAAC,GAAQ,EAAK,SAAW,EAC3B,OAKF,KAAK,WAAa,GAClB,KAAK,qBAAuB,KAG5B,KAAK,aAAa,EAAK,EAGvB,IAAM,EAAiB,KAAK,kBAAkB,EAG9C,KAAK,OAAO,UAAY,GAExB,IAAK,IAAM,KAAK,EACV,aAAa,GACf,KAAK,OAAO,YAAY,KAAK,eAAe,CAAC,CAAC,EAG5C,aAAa,GACf,KAAK,OAAO,YAAY,KAAK,aAAa,CAAC,CAAC,EAiBhD,GAZK,EAAiB,EAAgB,KAAK,kBAAkB,CAAC,GAC5D,KAAK,OAAO,cAAc,IAAI,MAAM,SAAU,CAAE,QAAS,EAAK,CAAC,CAAC,EAIlE,KAAK,aAAa,EAAI,EAGtB,KAAK,WAAa,GAId,KAAK,uBAAyB,KAAM,CACtC,IAAM,EAAiC,KAAK,qBACxC,EAAQ,OAAS,GAAK,KAAK,iBAC7B,KAAK,qBAAuB,KAE5B,KAAK,aAAa,EAAK,EACvB,KAAK,gBAAgB,CAAO,EAC5B,KAAK,aAAa,EAAI,GAGtB,KAAK,qBAAuB,IAEhC,CACF,CAEA,eAAsB,EAAyC,CAC7D,IAAM,EAAa,SAAS,cAAc,UAAU,EASpD,GARA,EAAW,GAAK,EAAS,GACzB,EAAW,MAAQ,EAAS,MACxB,EAAS,YACX,EAAW,QAAQ,UAAY,QAE7B,EAAS,WAAa,QACxB,EAAW,QAAQ,SAAW,EAAS,UAErC,EAAS,QACX,IAAK,IAAM,KAAU,EAAS,QAC5B,EAAW,YAAY,KAAK,aAAa,CAAgB,CAAC,EAG9D,OAAO,CACT,CAEA,aAAoB,EAAiC,CACnD,IAAM,EAAW,SAAS,cAAc,QAAQ,EAgChD,MA/BA,GAAS,GAAK,EAAK,GACnB,EAAS,MAAQ,EAAK,MACtB,EAAS,YAAc,EAAK,KACxB,EAAK,OAAS,IAChB,EAAS,aAAa,YAAa,EAAK,IAAI,EAE9C,EAAS,gBAAkB,EAAK,gBAChC,EAAS,SAAW,EAAK,SACrB,EAAK,WACP,EAAS,SAAW,IAEjB,EAAK,UACR,EAAS,MAAM,QAAU,QAEvB,EAAK,aACP,EAAS,aAAa,mBAAoB,MAAM,EAE9C,EAAK,WACP,EAAS,aAAa,iBAAkB,MAAM,EAE5C,EAAK,OACP,EAAK,MAAM,MAAM,GAAG,CAAC,CAAC,QAAS,GAAwB,CACrD,EAAS,UAAU,IAAI,CAAW,CACpC,CAAC,EAEC,EAAK,MAAQ,OAAO,EAAK,MAAS,UACpC,OAAO,KAAK,EAAK,IAAI,CAAC,CAAC,QAAS,GAAQ,CACtC,EAAS,aAAa,QAAU,EAAU,CAAG,EAAG,EAAK,KAAK,EAAI,CAChE,CAAC,EAGI,CACT,CAGA,oBAAkC,CAChC,IAAM,EAA6B,CAAC,EAG9B,EAAW,KAAK,OAAO,GACzB,GAIF,SAH6B,iBAC3B,cAAc,EAAS,GAEzB,CAAA,CAAY,QAAS,GAAU,EAAO,KAAK,CAAK,CAAC,EAInD,IAAI,EAAS,KAAK,OAAO,cACzB,KAAO,GAAU,IAAW,SAAS,MAAM,CACzC,GAAI,EAAO,UAAY,QAAS,CAC9B,EAAO,KAAK,CAA0B,EACtC,KACF,CACA,EAAS,EAAO,aAClB,CAKA,MAF2B,KAAK,IAAI,IAAI,CAAM,CAE9C,CAAA,CAAa,QAAS,GAAU,CAE9B,GAAK,EAAc,yBACjB,OAIF,IAAM,EAAqB,GAAkB,CAC3C,IAAM,EAAS,EAAE,OAGX,EAAsB,EAC1B,EACA,KAAK,OAAO,QAAQ,EACtB,EAKA,EAAE,eAAe,EAKb,CAAC,GAAuB,KAAK,cAC/B,KAAK,aAAa,CAEtB,EAGC,EAAe,yBAA2B,EAC3C,EAAM,iBAAiB,QAAS,EAAmB,CACjD,QAAS,GACT,QAAS,EACX,CAAC,CACH,CAAC,CACH,CAGA,qBAAmC,CACjC,IAAM,EAA6B,CAAC,EAG9B,EAAW,KAAK,OAAO,GACzB,GAIF,SAH6B,iBAC3B,cAAc,EAAS,GAEzB,CAAA,CAAY,QAAS,GAAU,EAAO,KAAK,CAAK,CAAC,EAInD,IAAI,EAAS,KAAK,OAAO,cACzB,KAAO,GAAU,IAAW,SAAS,MAAM,CACzC,GAAI,EAAO,UAAY,QAAS,CAC9B,EAAO,KAAK,CAA0B,EACtC,KACF,CACA,EAAS,EAAO,aAClB,CAKA,MAF2B,KAAK,IAAI,IAAI,CAAM,CAE9C,CAAA,CAAa,QAAS,GAAU,CAC9B,IAAM,EAAW,EAAc,yBAC3B,IACF,EAAM,oBAAoB,QAAS,EAAS,CAAE,QAAS,EAAK,CAAC,EAC7D,OAAQ,EAAc,yBAE1B,CAAC,CACH,CAEA,SAAiB,CACf,KAAK,aAAa,EAAK,EAGvB,KAAK,OAAO,oBAAoB,SAAU,KAAK,WAAW,EAG1D,AAIE,KAAK,uBAHL,KAAK,OAAO,oBAAoB,QAAS,KAAK,oBAAqB,CACjE,QAAS,EACX,CAAC,EAC0B,MAE7B,AAME,KAAK,gCALL,KAAK,OAAO,oBACV,YACA,KAAK,6BACL,CAAE,QAAS,EAAK,CAClB,EACoC,MAEtC,AAIE,KAAK,4BAHL,KAAK,OAAO,oBAAoB,QAAS,KAAK,yBAA0B,CACtE,QAAS,EACX,CAAC,EAC+B,MAElC,AAIE,KAAK,2BAHL,KAAK,OAAO,oBAAoB,OAAQ,KAAK,wBAAyB,CACpE,QAAS,EACX,CAAC,EAC8B,MAIjC,AAEE,KAAK,YADL,KAAK,SAAS,WAAW,EACT,MAIlB,KAAK,oBAAoB,EAGzB,OAAO,KAAK,OAAO,QAAQ,GAG3B,KAAK,OAAO,CACd,CACF,ECzrBA,SAAgB,EACd,EACA,EACS,CACT,OAAO,EAAmB,EAAM,QAAQ,EAAK,EAAG,CAAI,CACtD,CAMA,SAAgB,EACd,EACA,EACU,CACV,IAAM,EAAY,MAAM,QAAQ,CAAM,EAAI,EAAS,CAAC,CAAM,EACpD,EAAU,EAAM,eAAe,EAAK,EACpC,EAAgB,CAAC,EAEvB,IAAK,IAAM,KAAS,EAAW,CAC7B,GAAI,EAAQ,KAAM,GAAW,EAAO,IAAM,CAAK,EAAG,CAChD,EAAI,KAAK,CAAK,EACd,QACF,CAGA,IAAK,IAAM,KAAU,EAAQ,OAAQ,GAAW,EAAO,OAAS,CAAK,EACnE,EAAI,KAAK,EAAO,EAAE,CAEtB,CAEA,OAAO,CACT,CAEA,IAAqB,EAArB,KAAqC,CAMf,KALpB,MAA8B,CAAC,EAC/B,eAAyB,GAEzB,UAAmB,GAEnB,YAAY,EAAwB,CAAhB,KAAA,KAAA,CAAiB,CAErC,QAAe,EAA0B,CAKvC,GAJA,KAAK,MAAM,KAAK,CAAM,EAIlB,EAAO,SAAW,SAAU,CACzB,KAAK,iBACR,KAAK,eAAiB,GACtB,mBAAqB,KAAK,MAAM,CAAC,GAEnC,MACF,CAIK,KAAK,WACR,KAAK,MAAM,CAEf,CAGA,OAAqB,CAGnB,GAFA,KAAK,eAAiB,GAElB,KAAK,MAAM,SAAW,EACxB,OAGF,IAAM,EAAQ,KAAK,cAAc,KAAK,KAAK,EAC3C,KAAK,MAAQ,CAAC,EAEd,KAAK,UAAY,GACjB,GAAI,CACF,IAAK,IAAM,KAAU,EACnB,KAAK,YAAY,CAAM,CAE3B,QAAU,CACR,KAAK,UAAY,GAEb,KAAK,MAAM,OAAS,GACtB,KAAK,MAAM,CAEf,CACF,CAQA,cAAsB,EAAqC,CACzD,IAAM,EAAe,EAAQ,KAAM,GAAM,EAAE,OAAS,WAAW,EACzD,EAAe,EAAQ,KAAM,GAAM,EAAE,OAAS,WAAW,EAE/D,GAAI,GAAgB,EAAc,CAChC,IAAM,EAAmB,EAAQ,OAC9B,GAAM,EAAE,OAAS,aAAe,EAAE,OAAS,WAC9C,EACM,EAAgB,EAAiB,EAAiB,OAAS,GAMjE,OAJI,GAAe,OAAS,YACnB,CAAC,CAAa,EAGhB,CACT,CAEA,IAAM,EAAmB,EAAQ,OAAQ,GAAM,EAAE,OAAS,WAAW,EAKrE,OAJI,EAAiB,OAAS,EACrB,CAAC,EAAiB,EAAiB,OAAS,EAAE,EAGhD,CACT,CAEA,YAAoB,EAA0B,CAC5C,OAAQ,EAAO,KAAf,CACE,IAAK,YACH,KAAK,eACH,EAAO,KACP,EAAO,OACP,EAAO,kBACP,EAAO,cACT,EACA,MACF,IAAK,YACH,KAAK,eACH,EAAO,OACP,EAAO,OACP,EAAO,iBAAmB,EAC5B,EACA,MACF,IAAK,YACH,KAAK,eAAe,EAAO,MAAM,EACjC,KACJ,CACF,CAOA,eACE,EACA,EACA,EAAoB,GACpB,EAAiB,GACX,CACN,GAAM,CAAE,QAAO,SAAQ,SAAQ,UAAW,KAAK,KAK/C,GAAI,CAAC,GAAkB,EAA0B,EAAO,CAAI,EAC1D,OAGF,IAAM,EAAW,EAAM,YAAY,EAE7B,EAAM,EAAM,kBAAkB,CAAI,EACxC,GAAI,EAAK,CACH,EAAO,MACT,EAAO,MAAM,CAAG,EACP,KAAK,KAAK,SACnB,KAAK,KAAK,QAAQ,CAAG,EAEvB,MACF,CAEA,EAAM,QAAQ,EAAM,CAAiB,EACrC,IAAM,EAAY,EAAM,QAAQ,EAAK,EAEhC,GACH,EAAM,gBAAgB,EAInB,GACH,EAAO,cAAc,CAAS,EAGhC,EAAO,aAAa,EACpB,EAAO,cAAc,CAAS,EAE1B,EAAO,aAAe,CAAC,EAAiB,EAAU,EAAM,YAAY,CAAC,GACvE,EAAO,YAAY,EAAM,mBAAmB,CAAC,CAEjD,CAOA,qBAAoC,CAClC,GAAM,CAAE,QAAO,UAAW,KAAK,KACzB,EAAkB,EAAM,mBAAmB,EAC3C,EAAiB,EAAM,kBAAkB,EAE/C,GAAI,CAAC,EAAO,gBAAgB,CAAc,EAAG,CAC3C,GAAI,EAAgB,OAAS,EAAG,CAC9B,EAAO,cAAc,CAAe,EACpC,MACF,CAGA,IAAM,EAAc,EACjB,eAAe,CAAC,CAChB,KACE,GACC,aAAgB,GAAU,EAAK,cAAgB,EACnD,EACF,GAAI,EAAa,CACf,EAAO,cAAc,CAAC,IAAI,EAAO,CAAE,GAAG,EAAa,SAAU,EAAK,CAAC,CAAC,CAAC,EACrE,MACF,CACF,CAGA,EAAO,mBAAmB,CAAc,CAC1C,CAOA,eACE,EACA,EACA,EACM,CACN,GAAM,CAAE,QAAO,SAAQ,SAAQ,UAAW,KAAK,KAEzC,EAAW,EAAM,YAAY,EAC7B,EAAM,EAAmB,EAAO,CAAM,EAE5C,GAAI,EAAiB,EAAU,CAAG,EAChC,OAGF,EAAM,cAAc,KAAM,CAAG,EAC7B,KAAK,oBAAoB,EACzB,EAAO,aAAa,EAEpB,IAAM,EAAc,EAAO,QAAQ,OAAO,MAAM,MAAM,KAAK,EACvD,IAAgB,GAMT,EAAO,gCAAgC,EAChD,EAAO,sBAAsB,EAE7B,EAAO,cAAc,EAAM,QAAQ,EAAK,CAAC,EARrC,EAAO,mBAAmB,EAC5B,EAAO,sBAAsB,EACpB,KAAK,KAAK,QACnB,KAAK,KAAK,OAAO,CAAW,EAS9B,GACA,EAAO,aACP,CAAC,EAAiB,EAAU,EAAM,YAAY,CAAC,GAE/C,EAAO,YAAY,EAAM,mBAAmB,CAAC,CAEjD,CAGA,eAAuB,EAA+B,CACpD,GAAM,CAAE,QAAO,SAAQ,SAAQ,UAAW,KAAK,KACzC,EAAW,EAAM,YAAY,EAE7B,EADc,EAAO,QAAQ,OAAO,MAAM,MAAM,KAC3B,IAAgB,IAAM,CAAC,CAAC,KAAK,KAAK,OACvD,EAAc,EAAO,OAAS,EAAO,MAAQ,GAE7C,EAAgB,GAAyC,CAC7D,IAAK,IAAM,KAAQ,EAAM,CACvB,GAAI,aAAgB,EAAU,CAC5B,GACE,EAAK,QAAQ,KAAM,IAAS,EAAI,OAAS,EAAI,QAAU,CAAW,EAElE,MAAO,GAET,QACF,CAEA,IAAK,EAAK,OAAS,EAAK,QAAU,EAChC,MAAO,EAEX,CAEA,MAAO,EACT,EAEA,GAAI,CAAC,EAAa,EAAM,QAAQ,EAAK,CAAC,EACpC,GAAI,EAAoB,CACtB,IAAM,EAAW,EAAM,eAAe,EACjC,EAAa,CAAQ,GACxB,EAAM,QAAQ,CAAC,GAAG,EAAU,IAAI,EAAO,CAAM,CAAC,EAAG,EAAI,EAEvD,EAAM,gBAAgB,CACxB,MACE,EAAM,UAAU,CAAM,EACtB,EAAM,gBAAgB,EAI1B,IAAM,EAAO,EAAM,QAAQ,EAAK,EAGhC,GAAI,EAAoB,CACtB,IAAM,EAAkB,EAAM,mBAAmB,EAC7C,EAAgB,OAAS,GAC3B,EAAO,cAAc,CAAe,CAExC,MACE,EAAO,cAAc,CAAI,EAG3B,EAAO,aAAa,EACpB,EAAO,cAAc,CAAI,EAErB,EAAO,aAAe,CAAC,EAAiB,EAAU,EAAM,YAAY,CAAC,GACvE,EAAO,YAAY,EAAM,mBAAmB,CAAC,CAEjD,CACF,kGC/UqB,EAArB,KAAgC,CAC9B,SAGA,SACA,WACA,OACA,MACA,OACA,KACA,UACA,aAEA,iBAA2B,EAG3B,OAAgB,CACd,OAAQ,IAAA,GACR,cAAe,EAAa,IACnB,EAAI,KAAK,YAAY,CAAC,CAAC,QAAQ,EAAO,YAAY,CAAC,IAAM,GAElE,QAAS,IAAA,GACT,aAAc,IAAA,GACd,YAAa,IAAA,GACb,WAAY,IAAA,GACZ,UAAW,IAAA,GACX,YAAa,IAAA,GACb,WAAY,IAAA,EACd,EAEA,YAAY,EAAgB,CAO1B,GALA,KAAK,SACH,OAAO,EAAO,QAAW,SACrB,SAAS,cAAc,EAAO,MAAM,EACpC,EAAO,OAET,CAAC,KAAK,SAAU,CACd,EAAO,QAAU,EAAO,OAAO,OACjC,EAAO,OAAO,MAAU,MAAM,+BAA+B,CAAC,EAEhE,MACF,CACA,GAAI,KAAK,SAAS,UAAY,SAAU,CAClC,EAAO,QAAU,EAAO,OAAO,OACjC,EAAO,OAAO,MAAU,MAAM,6BAA6B,CAAC,EAE9D,MACF,CAGI,KAAK,SAAS,QAAQ,MACxB,KAAK,QAAQ,EAIf,KAAK,SAAW,IAAI,EAAS,EAAO,QAAQ,EAG5C,KAAK,WAAa,IAAI,EAAW,EAAO,UAAU,EAGlD,IAAM,EAAiB,CAAC,aAAc,YAAa,YAAY,EAC/D,IAAK,IAAM,KAAO,EAAO,OAElB,EAAO,OAAO,eAAe,CAAG,IAKjC,EAAe,QAAQ,CAAG,IAAM,GAMjC,KAAM,OAAkC,GACvC,EAAO,OACP,GAPD,KAAM,OAAkC,GAAO,EAC7C,EAAO,OAAkC,GAC1C,GACF,GASJ,KAAK,SAAS,SAAW,EAAO,UAAU,SACtC,EAAO,SAAS,SAChB,KAAK,SAAS,SAClB,KAAK,SAAS,WAAa,KAAK,SAAS,SACzC,KAAK,SAAS,MAAQ,KAAK,SAAS,MAAM,QAC1C,KAAK,SAAS,MAAQ,KAAK,SAAS,UAAU,MAAM,GAAG,EAGvD,KAAK,OAAS,IAAI,EAAO,KAAK,QAAQ,EAEjC,KAAK,SAAS,KACjB,KAAK,SAAS,GAAK,KAAK,SAAS,IAEnC,KAAK,OAAO,aACV,KAAK,SAAS,GACd,KAAK,SAAS,MACd,KAAK,SAAS,KAChB,EACA,KAAK,OAAO,OAAO,EAEnB,KAAK,OAAO,cAAiB,GAAsB,CAEjD,KAAK,SAAS,MAAQ,EAGtB,KAAK,OAAO,kBAAkB,CAChC,EACA,KAAK,OAAO,iBAAoB,GAAsB,CAChD,EACF,KAAK,QAAQ,EAEb,KAAK,OAAO,CAEhB,EAIA,KAAK,OAAO,iBAAqB,CAC1B,KAAK,SAAS,WACjB,KAAK,SAAS,OACV,KAAK,MAAM,CAAE,OAAQ,SAAU,iBAAkB,EAAM,CAAC,EACxD,KAAK,KAAK,EAElB,EAGA,IAAM,EAAO,EAAO,KAAO,EAAO,KAAO,KAAK,OAAO,QAAQ,EAC7D,KAAK,MAAQ,IAAI,EACf,KAAK,SAAS,WAAa,WAAa,SACxC,CACF,EAGI,EAAO,MACT,KAAK,OAAO,cAAc,KAAK,MAAM,QAAQ,CAAC,EAIhD,IAAM,EAAkB,CACtB,KAAM,KAAK,KAAK,KAAK,IAAI,EACzB,MAAO,KAAK,MAAM,KAAK,IAAI,EAC3B,QAAS,KAAK,OAAO,QAAU,KAAK,OAAO,QAAU,IAAA,GAErD,aAAc,EAA2B,IAA4B,CACnE,KAAK,KAAK,QAAQ,CAChB,KAAM,YACN,SACA,OAAQ,KACR,gBACF,CAAC,CACH,EACA,UAAY,GAA4B,CACtC,KAAK,KAAK,QAAQ,CAChB,KAAM,YACN,SACA,OAAQ,IACV,CAAC,CACH,EACA,OAAQ,KAAK,OAAO,KAAK,IAAI,EAC7B,aAAc,KAAK,OAAO,aAC1B,YAAa,KAAK,OAAO,WAC3B,EAGA,KAAK,SAAS,WACZ,EAAO,UAAU,YAAc,EAAuB,KAAK,QAAQ,EAErE,KAAK,OAAS,IAAI,EAChB,KAAK,SACL,KAAK,WACL,KAAK,MACL,CACF,EAGA,KAAK,SAAS,aAAe,EAC3B,KAAK,OAAO,QAAQ,KACpB,EAAO,UAAU,YACnB,EAGA,KAAK,KAAO,IAAI,EAAgB,CAC9B,OAAQ,KAAK,OACb,MAAO,KAAK,MACZ,OAAQ,KAAK,OACb,OAAQ,KAAK,OACb,OAAQ,KAAK,OAAO,KAAK,IAAI,CAC/B,CAAC,EAED,KAAK,OAAO,cAAiB,GAAsB,CACjD,KAAK,KAAK,QAAQ,CAChB,KAAM,YACN,OAAQ,EAAQ,IAAK,GAAW,EAAO,EAAE,EACzC,OAAQ,QACV,CAAC,CACH,EACA,KAAK,OAAO,gBAAmB,GAAgC,CAC7D,KAAK,KAAK,QAAQ,CAChB,KAAM,YACN,KAAM,GAAQ,CAAC,EACf,OAAQ,QACV,CAAC,CACH,EAGA,KAAK,UAAY,IAAI,EACnB,CACE,WAAY,KAAK,OAAO,WACxB,UAAW,KAAK,OAAO,UACvB,YAAc,GAAS,KAAK,OAAO,cAAc,CAAI,EACrD,QAAU,GAAS,KAAK,WAAW,CAAI,EACvC,eAAkB,CAChB,KAAK,OAAO,sBAAsB,EAClC,KAAK,OAAO,mBAAmB,EAC3B,KAAK,OAAO,YACd,KAAK,OAAO,WAAW,CAE3B,EACA,gBAAmB,KAAK,aAAa,oBAAoB,EACzD,iBAAoB,KAAK,aAAa,oBAAoB,CAC5D,EACA,CACE,aAAc,KAAK,SAAS,aAC5B,kBAAmB,EAAO,IACxB,KAAK,OAAO,iBAAiB,EAAO,CAAM,CAC9C,CACF,EAGA,KAAK,aAAe,IAAI,EAAa,CACnC,gBAAiB,KAAK,cAAc,KAAK,IAAI,EAC7C,mBAAsB,CAChB,CAAC,KAAK,SAAS,QAAU,CAAC,KAAK,SAAS,YAG5C,KAAK,OAAO,YAAY,CAC1B,EACA,mBAAsB,CAChB,CAAC,KAAK,SAAS,QAAU,CAAC,KAAK,SAAS,YAG5C,KAAK,OAAO,YAAY,CAC1B,EACA,uBAA0B,CACpB,SAAS,QACX,KAAK,MAAM,CAAE,OAAQ,MAAO,iBAAkB,EAAM,CAAC,CAEzD,CACF,CAAC,EAED,KAAK,OAAO,aAAa,EACzB,KAAK,OAAO,cAAc,KAAK,MAAM,QAAQ,EAAK,CAAC,EAGnD,IAAM,EAAkB,KAAK,SAAS,aAAa,YAAY,EACzD,EAAuB,KAAK,SAAS,aAAa,iBAAiB,EAEzE,GAAI,EACF,KAAK,OAAO,KAAK,KAAK,aAAa,aAAc,CAAe,OAC3D,GAAI,EACT,KAAK,OAAO,KAAK,KAAK,gBAAgB,YAAY,EAClD,KAAK,OAAO,KAAK,KAAK,aACpB,kBACA,CACF,OACK,GAAI,KAAK,SAAS,QAAU,KAAK,SAAS,OAAO,OAAS,EAAG,CAClE,IAAM,EAAgB,MAAM,KAAK,KAAK,SAAS,MAAM,CAAC,CAAC,KAAK,EAAO,KACjE,AACE,EAAM,KAAK,GAAG,KAAK,SAAS,GAAG,SAAS,IAEnC,EAAM,GACd,EACD,KAAK,OAAO,KAAK,KAAK,gBAAgB,YAAY,EAClD,KAAK,OAAO,KAAK,KAAK,aACpB,kBACA,EAAc,KAAK,GAAG,CACxB,CACF,CAGI,KAAK,SAAS,YAChB,KAAK,SAAS,WAAW,aACvB,KAAK,OAAO,KAAK,KACjB,KAAK,SAAS,WAChB,EAGF,KAAK,aAAa,OAAO,CACvB,aAAc,KAAK,SAAS,eAAiB,MAC/C,CAAC,EAGG,KAAK,SAAS,UAChB,KAAK,QAAQ,EAIX,KAAK,SAAS,YAChB,KAAK,KAAK,EAIZ,KAAK,OAAO,mBAAmB,EAG9B,KAAM,SAAiB,KAAO,IACjC,CAGA,QAAsB,CACpB,KAAK,SAAS,SAAW,GAEzB,KAAK,OAAO,OAAO,EACnB,KAAK,OAAO,OAAO,CACrB,CAGA,SAAuB,CACrB,KAAK,SAAS,SAAW,GAEzB,KAAK,OAAO,QAAQ,EACpB,KAAK,OAAO,QAAQ,CACtB,CAEA,SAAwC,CACtC,OAAO,KAAK,MAAM,QAAQ,CAC5B,CAEA,QAAe,EAAqD,CAElE,KAAK,KAAK,QAAQ,CAChB,KAAM,YACN,OACA,OAAQ,KACV,CAAC,CACH,CAEA,aAA+B,CAC7B,IAAI,EAAU,KAAK,MAAM,mBAAmB,EAI5C,OAHI,KAAK,SAAS,YAChB,EAAU,KAAK,MAAM,qBAAqB,CAAO,GAE5C,EAAQ,IAAK,GAAW,EAAO,KAAK,CAC7C,CAGA,YAAmB,EAA2B,EAAiB,GAAY,CAEzE,KAAK,KAAK,QAAQ,CAChB,KAAM,YACN,SACA,OAAQ,MACR,gBACF,CAAC,CACH,CAEA,UAAiB,EAA+B,CAC9C,KAAK,KAAK,QAAQ,CAChB,KAAM,YACN,SACA,OAAQ,KACV,CAAC,CACH,CAEA,MAAoB,CAGlB,GAAI,KAAK,SAAS,UAAY,KAAK,SAAS,OAC1C,OAIF,KAAK,UAAU,cAAc,EAG7B,KAAK,OAAO,KAAK,EAGb,KAAK,SAAS,YAAc,KAAK,SAAS,aAC5C,KAAK,OAAO,YAAY,EAG1B,KAAK,SAAS,OAAS,GAGvB,KAAU,UAAU,YAAY,CAAC,CAAC,SAAW,CAEtC,KAAK,SAAS,SAGnB,KAAK,SAAS,WAAa,KAAK,UAAU,WAC1C,KAAK,SAAS,OAAS,KAAK,UAAU,OACxC,CAAC,EAIC,KAAK,SAAS,kBAAoB,YAClC,CAAC,KAAK,OAAO,kBAAkB,GAE/B,KAAK,OAAO,sBAAsB,EAGpC,IAAM,EAAc,KAAK,OAAO,QAAQ,OAAO,MAAM,MAAM,KAAK,EAC5D,IAAgB,IAClB,KAAK,OAAO,CAAW,CAE3B,CAEA,MACE,EAAkB,CAAE,OAAQ,MAAO,iBAAkB,EAAM,EACrD,CAGF,CAAC,KAAK,SAAS,QAAU,KAAK,SAAS,YAI3C,KAAU,UAAU,aAAa,CAAI,CAAC,CAAC,KAAM,GAAW,CACjD,IAKD,KAAK,SAAS,SAIlB,KAAK,SAAS,OAAS,KAAK,UAAU,OACtC,KAAK,SAAS,WAAa,KAAK,UAAU,YAC5C,CAAC,CACH,CAGA,WAAmB,EAAuB,CAExC,KAAK,OAAO,MAAM,EAIhB,CAAC,KAAK,SAAS,YACf,KAAK,OAAO,QAAQ,OAAO,MAAM,QAAU,KAE3C,KAAK,KAAK,MAAM,EAChB,KAAK,OAAO,EAAE,GAIhB,IAAM,EACJ,EAAK,SAAW,WAAa,EAAK,SAAW,SAC/C,KAAK,OAAO,UAAU,EAAc,QAAU,IAAI,EAGlD,KAAK,SAAS,OAAS,GACvB,KAAK,SAAS,WAAa,GAE3B,KAAK,OAAO,qBAAqB,CACnC,CAGA,OAAc,EAAqB,CACjC,IAAM,EAAU,EAAM,KAAK,EAE3B,GAAI,IAAY,GAAI,CAClB,KAAK,OAAO,QAAQ,OAAO,MAAM,MAAQ,GACzC,KAAK,YAAY,EACjB,MACF,CAOA,GAJI,KAAK,OAAO,QAAQ,OAAO,MAAM,QAAU,IAC7C,KAAK,OAAO,QAAQ,OAAO,MAAM,MAAQ,GAGvC,KAAK,OAAO,OAAQ,CACtB,KAAK,aAAa,CAAO,EACzB,MACF,CAEA,KAAK,eAAe,CAAO,CAC7B,CAEA,aAA4B,CAG1B,GAFA,KAAK,mBAED,CAAC,KAAK,OAAO,QAAU,KAAK,OAAO,wBAAwB,EAAG,CAChE,KAAK,OAAO,qBAAqB,GAAI,KAAK,OAAO,YAAa,EAC9D,KAAK,OAAO,uBAAuB,EACnC,MACF,CAEA,KAAK,OAAO,uBAAuB,EACnC,KAAK,KAAK,QAAQ,CAChB,KAAM,YACN,KAAM,KAAK,MAAM,eAAe,EAChC,OAAQ,MACR,kBAAmB,EACrB,CAAC,CACH,CAEA,eAAuB,EAAqB,CAC1C,GAAI,KAAK,OAAO,wBAAwB,EAAG,CACzC,KAAK,OAAO,qBAAqB,EAAO,KAAK,OAAO,YAAa,EACjE,MACF,CAEA,IAAM,EAAgB,KAAK,MAAM,OAAO,EAAO,KAAK,OAAO,YAAa,EACxE,KAAK,OAAO,cAAc,CAAa,CACzC,CAEA,aAAqB,EAAqB,CACxC,IAAM,EAAa,EAAE,KAAK,iBAC1B,KAAK,OAAO,gBAAgB,EAE5B,IAAM,EAAa,KAAK,OAAO,OAC7B,EACA,KAAK,MAAM,mBAAmB,EAC9B,KAAK,MAAM,eAAe,CAC5B,EAEM,EACJ,GACS,CACL,IAAe,KAAK,kBAGpB,KAAK,OAAO,QAAQ,OAAO,MAAM,MAAM,KAAK,IAAM,GAItD,KAAK,KAAK,QAAQ,CAChB,KAAM,YACN,OACA,OAAQ,MACR,kBAAmB,GACnB,eAAgB,EAClB,CAAC,CACH,EAEA,GAAI,aAAsB,QAAS,CACjC,EAAW,KAAK,CAAY,CAAC,CAAC,MAAO,GAAwB,CACvD,IAAe,KAAK,kBAGxB,KAAK,OAAO,YAAY,OAAO,GAAQ,SAAW,EAAM,EAAI,OAAO,CACrE,CAAC,EAED,MACF,CAEA,GAAI,MAAM,QAAQ,CAAU,EAAG,CAC7B,EAAa,CAAU,EACvB,MACF,CAEA,KAAK,OAAO,YACV,wDACF,CACF,CAEA,SAAuB,CACrB,KAAK,UAAU,QAAQ,EAEvB,KAAK,OAAO,qBAAqB,EAEjC,KAAK,aAAa,OAAO,CACvB,aAAc,KAAK,SAAS,eAAiB,MAC/C,CAAC,EAGD,KAAK,MAAM,QAAQ,CAAC,CAAC,EAGrB,KAAK,OAAO,QAAQ,EAGpB,KAAK,OAAO,QAAQ,EAEpB,OAAQ,KAAK,SAAuD,IACtE,CAGA,cAAsB,EAAgB,CAE/B,KAAK,SAAS,QAMjB,EAAE,QACF,CAAC,EAAe,EAAE,OAAuB,KAAK,SAAS,EAAE,GAEzD,KAAK,MAAM,CAAE,OAAQ,UAAW,iBAAkB,EAAM,CAAC,CAE7D,CACF,SCvoBA,OAAO,OAAO,EAAY,CAAY"}