From 60eb6e5e0d0b20a7ec030484c576238a58d5bd5c Mon Sep 17 00:00:00 2001 From: gnbm Date: Mon, 10 Aug 2026 13:27:48 +0100 Subject: [PATCH 1/2] Increment version to 1.4.0 --- dist-archive/virtual-select-1.4.0.min.css | 13 + dist-archive/virtual-select-1.4.0.min.js | 5 + dist/virtual-select.js | 1044 ++++++++++++++++++--- dist/virtual-select.min.css | 4 +- dist/virtual-select.min.js | 4 +- docs/assets/virtual-select.js | 1044 ++++++++++++++++++--- docs/assets/virtual-select.min.css | 4 +- docs/assets/virtual-select.min.js | 4 +- package-lock.json | 16 +- package.json | 2 +- 10 files changed, 1869 insertions(+), 271 deletions(-) create mode 100644 dist-archive/virtual-select-1.4.0.min.css create mode 100644 dist-archive/virtual-select-1.4.0.min.js diff --git a/dist-archive/virtual-select-1.4.0.min.css b/dist-archive/virtual-select-1.4.0.min.css new file mode 100644 index 0000000..fb800b3 --- /dev/null +++ b/dist-archive/virtual-select-1.4.0.min.css @@ -0,0 +1,13 @@ +/*! + * Virtual Select v1.4.0 + * https://sa-si-dev.github.io/virtual-select + * Licensed under MIT (https://github.com/sa-si-dev/virtual-select/blob/master/LICENSE) + */ +@keyframes vscomp-animation-spin{to{transform:rotateZ(360deg)}}.vscomp-popup-active{overflow:hidden !important}.vscomp-ele{display:inline-block;max-width:250px;width:100%}.vscomp-wrapper{color:#333;display:inline-flex;flex-wrap:wrap;font-family:sans-serif;font-size:14px;position:relative;text-align:left;width:100%}.vscomp-wrapper *,.vscomp-wrapper *::before,.vscomp-wrapper *::after{box-sizing:border-box}.vscomp-wrapper:focus{outline:none}.vscomp-dropbox-wrapper{left:0;position:absolute;top:0}.vscomp-toggle-button{align-items:center;background-color:#fff;border:1px solid #ddd;cursor:pointer;display:flex;padding:7px 30px 7px 10px;position:relative;width:100%}.vscomp-value{height:20px;line-height:20px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vscomp-arrow{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;width:30px}.vscomp-arrow::after{transform:rotate(45deg);border:1px solid rgba(0,0,0,0);border-bottom-color:#111;border-right-color:#111;content:"";height:8px;margin-top:-6px;width:8px}.vscomp-clear-icon{height:12px;position:relative;width:12px}.vscomp-clear-icon::before,.vscomp-clear-icon::after{background-color:#999;content:"";height:12px;left:5px;position:absolute;top:0;width:2px}.vscomp-clear-icon::before{transform:rotate(45deg)}.vscomp-clear-icon::after{transform:rotate(-45deg)}.vscomp-clear-icon:hover::before,.vscomp-clear-icon:hover::after{background:#333}.vscomp-clear-button{align-items:center;border-radius:50%;display:none;height:24px;justify-content:center;margin-top:-12px;position:absolute;right:30px;top:50%;width:24px}.vscomp-clear-button:hover{background:#ccc}.vscomp-clear-button:hover .vscomp-clear-icon::before,.vscomp-clear-button:hover .vscomp-clear-icon::after{background-color:#333}.vscomp-dropbox-close-button{align-items:center;background-color:#fff;border-radius:50%;bottom:-48px;cursor:pointer;display:none;height:40px;justify-content:center;left:50%;margin-left:-20px;position:absolute;width:40px}.vscomp-value-tag.more-value-count{white-space:nowrap}.vscomp-dropbox-container{width:100%;z-index:2}.vscomp-dropbox{background-color:#fff;width:100%}.vscomp-options-container{max-height:210px;overflow:auto;position:relative}.vscomp-options-bottom-freezer{bottom:0;height:2px;left:0;position:absolute;right:0}.vscomp-option{align-items:center;cursor:pointer;display:flex;flex-wrap:wrap;height:40px;padding:0 15px;position:relative}.vscomp-option.selected{background-color:#eee}.vscomp-option.focused{background-color:#ccc}.vscomp-option.disabled{cursor:default;opacity:.5}.vscomp-option.group-title .vscomp-option-text{cursor:default;opacity:.6}.vscomp-option.group-title.selected{background-color:rgba(0,0,0,0)}.vscomp-option.group-option{padding-left:30px}.vscomp-new-option-icon{height:30px;position:absolute;right:0;top:0;width:30px}.vscomp-new-option-icon::before{border:15px solid #512da8;border-bottom-color:rgba(0,0,0,0);border-left-color:rgba(0,0,0,0);content:"";position:absolute;right:0;top:0}.vscomp-new-option-icon::after{align-items:center;color:#fff;content:"+";display:flex;font-size:18px;height:15px;justify-content:center;position:absolute;right:1px;top:0;width:15px}.vscomp-option-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;-webkit-user-select:none;user-select:none;width:100%}.vscomp-option-description{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#666;font-size:13px;line-height:15px;width:100%}.vscomp-search-container{align-items:center;border-bottom:1px solid #ddd;display:flex;height:40px;padding:0 5px 0 15px;position:relative}.vscomp-search-label,.vscomp-live-region,.vscomp-dropbox-container-top,.vscomp-dropbox-container-bottom{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.vscomp-search-input{background-color:rgba(0,0,0,0);border:0;color:inherit;font-size:15px;height:38px;padding:10px 0;width:calc(100% - 30px)}.vscomp-search-input:focus{outline:none}.vscomp-search-clear{align-items:center;color:#999;cursor:pointer;display:flex;font-size:25px;height:30px;justify-content:center;-webkit-user-select:none;user-select:none;visibility:hidden;width:30px}.vscomp-search-clear:hover{color:inherit}.vscomp-error-message{align-items:flex-start;color:#b00020;display:none;font-size:13px;gap:4px;line-height:1.4;padding-top:4px;width:100%}.vscomp-error-message::before{content:"\26A0";flex:none;font-size:1.1em;line-height:1.2}.vscomp-no-options,.vscomp-no-search-results{align-items:center;display:none;justify-content:center;padding:20px 10px}.vscomp-options-loader{display:none;padding:20px 0;text-align:center}.vscomp-options-loader::before{animation:vscomp-animation-spin .8s infinite linear;background-color:#fff;border-radius:50%;box-shadow:-4px -5px 3px -3px rgba(0,0,0,.3);content:"";display:inline-block;height:40px;opacity:.7;width:40px}.vscomp-ele[disabled]{cursor:not-allowed;-webkit-user-select:none;user-select:none}.vscomp-ele[disabled] .vscomp-wrapper{opacity:.7;pointer-events:none}.vscomp-wrapper .checkbox-icon{display:inline-flex;height:15px;margin-right:10px;position:relative;width:15px}.vscomp-wrapper .checkbox-icon::after{transition-duration:.2s;border:2px solid #888;content:"";display:inline-block;height:100%;width:100%}.vscomp-wrapper .checkbox-icon.checked::after{transform:rotate(45deg) translate(1px, -4px);border-color:#512da8;border-left-color:rgba(0,0,0,0);border-top-color:rgba(0,0,0,0);width:50%}.vscomp-wrapper.show-as-popup .vscomp-dropbox-container{align-items:center;background-color:rgba(0,0,0,.5);display:flex;height:100vh;justify-content:center;left:0;opacity:1;overflow:auto;padding:0 10px;position:fixed;top:0;width:100vw}.vscomp-wrapper.show-as-popup .vscomp-dropbox{margin-top:-24px;max-height:calc(80% - 48px);max-width:500px;position:relative;width:80%}.vscomp-wrapper.show-as-popup .vscomp-dropbox-close-button{display:flex}.vscomp-wrapper.popup-position-left .vscomp-dropbox-container{justify-content:flex-start}.vscomp-wrapper.popup-position-right .vscomp-dropbox-container{justify-content:flex-end}.vscomp-wrapper.has-select-all .vscomp-toggle-all-button{align-items:center;cursor:pointer;display:flex;min-height:24px;min-width:24px}.vscomp-wrapper.has-select-all .vscomp-search-input,.vscomp-wrapper.has-select-all .vscomp-toggle-all-label{width:calc(100% - 55px)}.vscomp-wrapper.has-select-all .vscomp-toggle-all-label{display:none}.vscomp-wrapper:not(.has-search-input) .vscomp-toggle-all-button{width:100%}.vscomp-wrapper:not(.has-search-input) .vscomp-toggle-all-label{display:inline-block}.vscomp-wrapper.multiple .vscomp-option .vscomp-option-text{width:calc(100% - 25px)}.vscomp-wrapper.multiple .vscomp-option .vscomp-option-description{padding-left:25px}.vscomp-wrapper.multiple .vscomp-option.selected .checkbox-icon::after{transform:rotate(45deg) translate(1px, -4px);border-color:#512da8;border-left-color:rgba(0,0,0,0);border-top-color:rgba(0,0,0,0);width:50%}.vscomp-wrapper.focused .vscomp-toggle-button,.vscomp-wrapper:focus .vscomp-toggle-button{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2)}.vscomp-wrapper.closed .vscomp-dropbox-container,.vscomp-wrapper.closed.vscomp-dropbox-wrapper{display:none}.vscomp-wrapper:not(.has-value) .vscomp-value{opacity:.5}.vscomp-wrapper.has-clear-button.has-value .vscomp-clear-button{display:flex}.vscomp-wrapper.has-clear-button .vscomp-toggle-button{padding-right:54px}.vscomp-wrapper.has-no-options .vscomp-options-container,.vscomp-wrapper.has-no-search-results .vscomp-options-container{display:none}.vscomp-wrapper.has-no-options .vscomp-no-options{display:flex}.vscomp-wrapper.has-no-search-results .vscomp-no-search-results{display:flex}.vscomp-wrapper.has-search-value .vscomp-search-clear{visibility:visible}.vscomp-wrapper.has-no-options .vscomp-toggle-all-button{opacity:.5;pointer-events:none}.vscomp-wrapper.keep-always-open .vscomp-toggle-button{padding-right:24px}.vscomp-wrapper.keep-always-open .vscomp-clear-button{right:5px}.vscomp-wrapper.keep-always-open .vscomp-arrow{display:none}.vscomp-wrapper.keep-always-open .vscomp-dropbox-container{position:relative;z-index:1}.vscomp-wrapper.keep-always-open .vscomp-dropbox{transition-duration:0s;border:1px solid #ddd;box-shadow:none}.vscomp-wrapper.keep-always-open.focused,.vscomp-wrapper.keep-always-open:focus,.vscomp-wrapper.keep-always-open:hover{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2)}.vscomp-wrapper.server-searching .vscomp-options-list{display:none}.vscomp-wrapper.server-searching .vscomp-options-loader{display:block}.vscomp-wrapper.has-error .vscomp-toggle-button{border-color:#b00020}.vscomp-wrapper.has-error~.vscomp-error-message{display:flex}.vscomp-wrapper.show-value-as-tags .vscomp-toggle-button{padding:4px 22px 0 10px}.vscomp-wrapper.show-value-as-tags .vscomp-value{display:flex;flex-wrap:wrap;height:auto;min-height:28px;overflow:auto;text-overflow:unset;white-space:normal}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;align-items:center;border:1px solid #ddd;border-radius:20px;display:inline-flex;font-size:12px;line-height:16px;margin:0 4px 4px 0;max-width:100%;padding:2px 3px 2px 8px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag.more-value-count{padding-right:8px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:calc(100% - 24px)}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-clear-button{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-clear-button .vscomp-clear-icon{transform:scale(0.8)}.vscomp-wrapper.show-value-as-tags .vscomp-arrow{height:34px}.vscomp-wrapper.show-value-as-tags .vscomp-clear-button{margin-top:0;top:5px}.vscomp-wrapper.show-value-as-tags.has-value .vscomp-arrow{display:none}.vscomp-wrapper.show-value-as-tags.has-value .vscomp-clear-button{right:2px}.vscomp-wrapper.show-value-as-tags:not(.has-value) .vscomp-toggle-button{padding-bottom:2px}.vscomp-wrapper.show-value-as-tags:not(.has-value) .vscomp-value{align-items:center;padding-bottom:3px}@media(prefers-reduced-motion: reduce){.vscomp-dropbox-container,.vscomp-dropbox,.vscomp-wrapper .vscomp-toggle-button,.vscomp-dropbox-wrapper{transition-duration:0s !important}}.vscomp-wrapper.text-direction-rtl{direction:rtl}.vscomp-wrapper.text-direction-rtl .vscomp-toggle-button{padding:7px 10px 7px 30px}.vscomp-wrapper.text-direction-rtl .vscomp-arrow{left:0;right:auto}.vscomp-wrapper.text-direction-rtl .vscomp-clear-button{left:30px;right:auto !important}.vscomp-wrapper.text-direction-rtl .checkbox-icon{margin-left:10px;margin-right:0}.vscomp-wrapper.text-direction-rtl .checkbox-icon.checked::after{transform:rotate(45deg) translate(-4px, 1px)}.vscomp-wrapper.text-direction-rtl .vscomp-search-container{padding:0 15px 0 5px}.vscomp-wrapper.text-direction-rtl .vscomp-toggle-all-label{text-align:right}.vscomp-wrapper.text-direction-rtl .vscomp-option{text-align:right}.vscomp-wrapper.text-direction-rtl .vscomp-option.group-option{padding-right:30px}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon{left:0;right:auto}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon::before{border-left-color:#512da8;border-right-color:rgba(0,0,0,0)}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon::after{left:1px;right:auto}.vscomp-wrapper.text-direction-rtl.multiple .vscomp-option.selected .checkbox-icon::after{transform:rotate(45deg) translate(-4px, 1px)}.vscomp-wrapper.text-direction-rtl.has-clear-button .vscomp-toggle-button{padding-left:54px}.vscomp-wrapper.text-direction-rtl.keep-always-open .vscomp-toggle-button{padding-left:24px}.vscomp-wrapper.text-direction-rtl.keep-always-open .vscomp-clear-button{left:5px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-toggle-button{padding:4px 10px 0 22px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-value-tag{margin:0 0 4px 4px;padding:2px 8px 2px 3px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-value-tag.more-value-count{padding-left:8px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags.has-value .vscomp-clear-button{left:2px} +/*! + * Popover v1.0.13 + * https://sa-si-dev.github.io/popover + * Licensed under MIT (https://github.com/sa-si-dev/popover/blob/master/LICENSE) + */ +.pop-comp-wrapper{display:none;position:absolute;top:0;left:0;opacity:0;color:#000;background-color:#fff;box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2);text-align:left;flex-wrap:wrap;z-index:1}.pop-comp-arrow{position:absolute;z-index:1;width:16px;height:16px;overflow:hidden;pointer-events:none}.pop-comp-arrow::before{content:"";position:absolute;top:8px;left:8px;width:16px;height:16px;background-color:#fff;box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2);-webkit-transform-origin:left top;transform-origin:left top;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.pop-comp-content{position:relative;z-index:2}.pop-comp-wrapper.position-bottom>.pop-comp-arrow{margin-left:-8px;left:0;top:-15px}.pop-comp-wrapper.position-bottom>.pop-comp-arrow::before{box-shadow:0px 0px 2px 0 rgba(0,0,0,.14)}.pop-comp-wrapper.position-top>.pop-comp-arrow{margin-left:-8px;left:0;bottom:-15px}.pop-comp-wrapper.position-right>.pop-comp-arrow{margin-top:-8px;top:0;left:-15px}.pop-comp-wrapper.position-left>.pop-comp-arrow{margin-top:-8px;top:0;right:-15px}.pop-comp-disable-events{pointer-events:none} + diff --git a/dist-archive/virtual-select-1.4.0.min.js b/dist-archive/virtual-select-1.4.0.min.js new file mode 100644 index 0000000..d6ca8ea --- /dev/null +++ b/dist-archive/virtual-select-1.4.0.min.js @@ -0,0 +1,5 @@ +/*! + * Virtual Select v1.4.0 + * https://sa-si-dev.github.io/virtual-select + * Licensed under MIT (https://github.com/sa-si-dev/virtual-select/blob/master/LICENSE) + */!function(){"use strict";const e=/[^\p{L}\p{N}_]/gu;class t{static getString(e){return e||0===e?e.toString():""}static convertToBoolean(e,t=!1){let s;return s=!0===e||"true"===e||!1!==e&&"false"!==e&&t,s}static isEmpty(e){let t=!1;return e?Array.isArray(e)?0===e.length&&(t=!0):"object"==typeof e&&0===Object.keys(e).length&&(t=!0):t=!0,t}static isNotEmpty(e){return!t.isEmpty(e)}static normalizeValues(e){if(Array.isArray(e)){const t=new Array(e.length);for(let s=0;s!!e):[]}static getRandomInt(e,t=0){const s=Math.ceil(t),i=Math.floor(e);return Math.floor(Math.random()*(i-s-1))+s}static regexEscape(e){return e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}static normalizeString(t){return t.normalize("NFD").replace(e,"")}static prefersReducedMotion(){return"function"==typeof window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}static replaceDoubleQuotesWithHTML(e){return e.replace(/"/g,""")}static escapeAttributeValue(e){return t.getString(e).replace(/&/g,"&").replace(/"/g,""")}static decodeSecureText(e){return t.getString(e).replace(/</g,"<").replace(/>/g,">").replace(/ /g," ").replace(/&/g,"&")}static getPlainText(e){return t.decodeSecureText(e).replace(/<[^>]+>/gi," ").replace(/\s+/g," ").trim()}static getAriaLabelText(e){return t.escapeAttributeValue(t.getPlainText(e))}static containsHTML(e){return/<[a-z][\s\S]*>/i.test(e)}static containsHTMLorJS(e){return/<([a-z]+)[\s\S]*?>|on\w+="[^"]*"/i.test(e)}static sanitizeClassNames(e){return e?String(e).replace(/["<>]/g,""):e}static throttle(e,t){let s,i=null,o=[],n=0;function r(){const t=s,i=o;o=[],s=void 0,e.apply(t,i)}function a(...e){const a=Date.now(),l=t-(a-n);o=e,s=this,l<=0||l>t?(i&&(clearTimeout(i),i=null),n=a,r()):i||(i=setTimeout(()=>{n=Date.now(),i=null,r()},l))}return a.cancel=function(){i&&(clearTimeout(i),i=null),n=0,o=[],s=void 0},a}}class s{static addClass(e,t){if(!e)return;const i=t.split(" ");s.getElements(e).forEach(e=>{e.classList.add(...i)})}static removeClass(e,t){if(!e)return;const i=t.split(" ");s.getElements(e).forEach(e=>{e.classList.remove(...i)})}static toggleClass(e,t,i){if(!e)return;let o;void 0!==i&&(o=Boolean(i)),s.getElements(e).forEach(e=>{e.classList.toggle(t,o)})}static hasClass(e,t){return!!e&&e.classList.contains(t)}static hasEllipsis(e){return!!e&&e.scrollWidth>e.offsetWidth}static getData(e,t,s){if(!e)return;let i=e?e.dataset[t]:"";return"number"===s?i=parseFloat(i)||0:"true"===i?i=!0:"false"===i&&(i=!1),i}static setData(e,t,s){e&&(e.dataset[t]=s)}static setAttr(e,t,s){e&&e.setAttribute(t,s)}static removeAttr(e,t){e&&e.removeAttribute(t)}static toggleAria(e,t,i,o="true"){e&&s.getElements(e).forEach(e=>{i?e.setAttribute(`aria-${t}`,o):e.removeAttribute(`aria-${t}`)})}static setAttrFromEle(e,t,s,i){const o={};s.forEach(t=>{o[t]=e.getAttribute(t)}),s.forEach(e=>{const s=o[e];(s||-1!==i.indexOf(e)&&""===s)&&t.setAttribute(e,s)})}static setStyle(e,t,s){e&&(e.style[t]=s)}static setStyles(e,t){e&&t&&Object.keys(t).forEach(s=>{e.style[s]=t[s]})}static setAria(e,t,s){if(!e)return;let i=t;"role"!==i&&(i=`aria-${i}`),e.setAttribute(i,s)}static getElements(e){return e?void 0===e.forEach?[e]:e:[]}static getElementsBySelector(e="",t=void 0){let s;const i=void 0!==t?t:document;return""!==e&&(s=i.querySelectorAll(e)),void 0!==s?Array.from(s):[]}static addEvent(e,i,o,n){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{s.getElements(e).forEach(e=>{e.addEventListener(t,o,{capture:n})})})}static dispatchEvent(e,t,i=!1){if(!e)return;const o=s.getElements(e);setTimeout(()=>{o.forEach(e=>{e.dispatchEvent(new CustomEvent(t,{bubbles:i}))})},0)}static getAttributesText(e){let s="";return e?(Object.entries(e).forEach(([e,i])=>{void 0!==i&&(s+=` ${e}="${t.replaceDoubleQuotesWithHTML(String(i))}" `)}),s):s}static convertPropToDataAttr(e){return e?`data-${e}`.replace(/([A-Z])/g,"-$1").toLowerCase():""}static changeTabIndex(e,t){e?s.getElements(e).forEach(e=>{e.tabIndex=t}):console.log(e,"Invalid element provided.")}static removeEvent(e,t,i,o=!1){e&&s.getElements(e).forEach(e=>{e.removeEventListener(t,i,{capture:o})})}}const i={13:"onEnterPress",38:"onUpArrowPress",40:"onDownArrowPress",46:"onBackspaceOrDeletePress",8:"onBackspaceOrDeletePress"},o=["autofocus","disabled","multiple","required"],n=["autofocus","class","disabled","id","multiple","name","placeholder","required"];let r;const a=["additionalClasses","additionalDropboxClasses","additionalDropboxContainerClasses","additionalToggleButtonClasses","aliasKey","allOptionsSelectedText","allowNewOption","alwaysShowSelectedOptionsCount","alwaysShowSelectedOptionsLabel","ariaLabelledby","ariaLabelText","ariaLabelClearButtonText","ariaLabelTagClearButtonText","ariaLabelSearchClearButtonText","autoSelectFirstOption","clearButtonText","descriptionKey","disableAllOptionsSelectedText","disableOptionGroupCheckbox","disableSelectAll","disableValidation","dropboxWidth","dropboxWrapper","emptyValue","enableSecureText","focusSelectedOptionOnOpen","hasOptionDescription","hideClearButton","hideValueTooltipOnSelectAll","keepAlwaysOpen","labelKey","markSearchResults","maxValues","maxWidth","minValues","loadingText","minValuesErrorText","moreText","noOfDisplayValues","noOptionsSelectedText","noOptionsText","noSearchResultsText","optionHeight","optionSelectedText","optionsCount","optionsSelectedText","popupDropboxBreakpoint","popupPosition","position","requiredErrorText","search","searchByStartsWith","searchDelay","searchFormLabel","searchGroup","searchNormalize","searchPlaceholderText","searchResultText","searchResultsText","selectAllOnlyVisible","selectAllText","selectedText","setValueAsArray","showDropboxAsPopup","showOptionsOnlyOnSearch","showSecureTextWarning","showSelectedOptionsFirst","showValueAsTags","silentInitialValueSet","textDirection","tooltipAlignment","tooltipFontSize","tooltipMaxWidth","updatePositionThrottle","useGroupValue","valueKey","zIndex"];class l{constructor(e){this.isDestroyed=!1;try{this.createSecureTextElements(),this.setProps(e),this.setDisabledOptions(e.disabledOptions),this.setOptions(e.options),this.warnIfSecureTextDisabled(),this.render()}catch(e){console.warn("Couldn't initiate Virtual Select"),console.error(e)}}render(){if(!this.$ele)return;const{uniqueId:e}=this;let i="vscomp-wrapper",o="vscomp-toggle-button";const n=this.showValueAsTags?"":this.getTooltipAttrText(this.placeholder,!0,!0),r=this.getTooltipAttrText(this.clearButtonText),a=this.ariaLabelledby?`aria-labelledby="${t.replaceDoubleQuotesWithHTML(t.getString(this.ariaLabelledby))}"`:"",l=this.ariaLabelText?`aria-label="${t.getAriaLabelText(this.ariaLabelText)}"`:"",h=this.ariaLabelClearButtonText?`aria-label="${t.getAriaLabelText(this.ariaLabelClearButtonText)}"`:"";let p=!1;this.additionalClasses&&(i+=` ${t.sanitizeClassNames(this.additionalClasses)}`),this.additionalToggleButtonClasses&&(o+=` ${t.sanitizeClassNames(this.additionalToggleButtonClasses)}`),this.multiple&&(i+=" multiple",this.disableSelectAll||(i+=" has-select-all")),this.hideClearButton||(i+=" has-clear-button"),this.keepAlwaysOpen?(i+=" keep-always-open",p=!0):i+=" closed",this.showAsPopup&&(i+=" show-as-popup"),this.hasSearch&&(i+=" has-search-input"),this.showValueAsTags&&(i+=" show-value-as-tags"),this.textDirection&&(i+=` text-direction-${this.textDirection}`),this.popupPosition&&(i+=` popup-position-${this.popupPosition.toLowerCase()}`);const c=`
\n \n
\n
\n ${this.placeholder}\n
\n
\n
\n \n
\n
\n\n ${this.renderDropbox({wrapperClasses:i})}\n
\n\n
\n\n
`;this.$ele.innerHTML=c,this.$body=document.querySelector("body"),this.$wrapper=this.$ele.querySelector(".vscomp-wrapper"),this.hasDropboxWrapper?(this.$allWrappers=[this.$wrapper,this.$dropboxWrapper],this.$dropboxContainer=this.$dropboxWrapper.querySelector(".vscomp-dropbox-container"),s.addClass(this.$dropboxContainer,"pop-comp-wrapper")):(this.$allWrappers=[this.$wrapper],this.$dropboxContainer=this.$wrapper.querySelector(".vscomp-dropbox-container")),this.$toggleButton=this.$ele.querySelector(".vscomp-toggle-button"),this.$clearButton=this.$ele.querySelector(".vscomp-clear-button"),this.$valueText=this.$ele.querySelector(".vscomp-value"),this.$hiddenInput=this.$ele.querySelector(".vscomp-hidden-input"),this.$hiddenInput.name=this.name,this.$liveRegion=this.$ele.querySelector(".vscomp-live-region"),this.$errorMessage=this.$ele.querySelector(".vscomp-error-message"),this.$dropbox=this.$dropboxContainer.querySelector(".vscomp-dropbox"),this.$dropboxCloseButton=this.$dropboxContainer.querySelector(".vscomp-dropbox-close-button"),this.$dropboxContainerBottom=this.$dropboxContainer.querySelector(".vscomp-dropbox-container-bottom"),this.$dropboxContainerTop=this.$dropboxContainer.querySelector(".vscomp-dropbox-container-top"),this.$search=this.$dropboxContainer.querySelector(".vscomp-search-wrapper"),this.$optionsContainer=this.$dropboxContainer.querySelector(".vscomp-options-container"),this.$optionsList=this.$dropboxContainer.querySelector(".vscomp-options-list"),this.$options=this.$dropboxContainer.querySelector(".vscomp-options"),this.$noOptions=this.$dropboxContainer.querySelector(".vscomp-no-options"),this.$noSearchResults=this.$dropboxContainer.querySelector(".vscomp-no-search-results"),this.afterRenderWrapper()}renderDropbox({wrapperClasses:e}){const i="self"!==this.dropboxWrapper?document.querySelector(this.dropboxWrapper):null;let o="vscomp-dropbox";this.additionalDropboxClasses&&(o+=` ${t.sanitizeClassNames(this.additionalDropboxClasses)}`);let n="vscomp-dropbox-container";this.additionalDropboxContainerClasses&&(n+=` ${t.sanitizeClassNames(this.additionalDropboxContainerClasses)}`);const r=`
\n \n
\n
\n\n
\n
\n\n
\n
\n
\n
\n\n
\n
${this.noOptionsText}
\n
${this.noSearchResultsText}
\n\n \n
\n \n
`;if(i){const t=document.createElement("div");return this.$dropboxWrapper=t,this.hasDropboxWrapper=!0,t.innerHTML=r,i.appendChild(t),s.addClass(t,`vscomp-dropbox-wrapper ${e}`),this.keepAlwaysOpen||(s.setAttr(t,"tabindex","-1"),s.setAria(t,"hidden",!0)),""}return this.hasDropboxWrapper=!1,r}renderOptions(){this.ariaMetadataDirty&&(this.calculateAriaMetadata(),this.ariaMetadataDirty=!1);let e="";const s=this.getVisibleOptions();let i="",o="";const n=!(!this.markSearchResults||!this.searchValue);let r;const{labelRenderer:a,disableOptionGroupCheckbox:l,uniqueId:h,searchGroup:p}=this,c="function"==typeof a,{convertToBoolean:u}=t;let d="";if(n&&(r=new RegExp(`(${t.regexEscape(this.searchValue)})(?!([^<]+)?>)`,"gi")),this.multiple&&(i=''),this.allowNewOption){const e=this.getTooltipAttrText("New Option");o=``}s.forEach(s=>{const{index:v}=s;let b,m="vscomp-option";const g=this.getTooltipAttrText("",!0,!0);let f=i,x="",S="",O="",y="",$="-1";const w=u(s.isSelected);let C="";if(s.classNames&&(m+=` ${t.sanitizeClassNames(s.classNames)}`),s.isFocused&&($="0",m+=" focused"),s.isDisabled&&(m+=" disabled",C='aria-disabled="true"'),s.isGroupTitle)if(d=t.getAriaLabelText(s.label),m+=" group-title",l)f="";else if(this.multiple){const e=t.getAriaLabelText(this.selectAllText);y=`aria-label="${d}, ${e}"`}if(w&&(m+=" selected"),s.isGroupOption)if(m+=" group-option",O=`data-group-index="${s.groupIndex}"`,s.customData){const e=t.getAriaLabelText(this.secureText(t.getString(s.customData.group_name))),i=t.getAriaLabelText(this.secureText(t.getString(s.customData.description)));d=void 0!==s.customData.group_name?`${e}, `:"";const o=void 0!==s.customData.description?` ${i},`:"";y=`aria-label="${d} ${t.getAriaLabelText(s.label)}, ${o}"`}else y=`aria-label="${d}, ${t.getAriaLabelText(s.label)}"`;b=c?a(s):s.label,s.description&&(S=`
${s.description}
`),s.isCurrentNew?(m+=" current-new",x+=o):!n||s.isGroupTitle&&!p||(b=b.replace(r,"$1"));let T="";this.ariaSetSize>0&&(T=`aria-setsize="${this.ariaSetSize}"`,s.filteredIndex&&(T+=` aria-posinset="${s.filteredIndex}"`));const E=t.escapeAttributeValue(s.value);e+=`
\n ${f}\n \n ${b}\n \n ${S}\n ${x}\n
`}),d="",this.$options.innerHTML=e,this.$visibleOptions=this.$options.querySelectorAll(".vscomp-option"),this.afterRenderOptions()}renderSearch(){if(!this.hasSearchContainer)return;let e="",s="";if(this.multiple&&!this.disableSelectAll&&(e=`\n \n ${this.selectAllText}\n `),this.hasSearch){const e=this.ariaLabelSearchClearButtonText?`aria-label="${t.getAriaLabelText(this.ariaLabelSearchClearButtonText)}"`:"";s=`\n \n ×`}const i=`
\n ${e}\n ${s}\n
`;this.$search.innerHTML=i,this.$searchInput=this.$dropboxContainer.querySelector(".vscomp-search-input"),this.$searchClear=this.$dropboxContainer.querySelector(".vscomp-search-clear"),this.$toggleAllButton=this.$dropboxContainer.querySelector(".vscomp-toggle-all-button"),this.$toggleAllCheckbox=this.$dropboxContainer.querySelector(".vscomp-toggle-all-checkbox"),this.addEvent(this.$searchInput,"input","onSearch"),this.addEvent(this.$searchInput,"change","preventPropagation"),this.addEvent(this.$searchClear,"click keydown","onSearchClear"),this.addEvent(this.$toggleAllButton,"click","onToggleAllOptions"),this.addEvent(this.$dropboxContainerBottom,"focus","onDropboxContainerTopOrBottomFocus"),this.addEvent(this.$dropboxContainerTop,"focus","onDropboxContainerTopOrBottomFocus")}addEvents(){this.addEvent(document,"click","onDocumentClick",!0),this.addEvent(this.$allWrappers,"keydown","onKeyDown"),this.addEvent(this.$toggleButton,"click keydown","onToggleButtonPress"),this.addEvent(this.$clearButton,"click keydown","onClearButtonClick"),this.addEvent(this.$dropboxContainer,"click","onDropboxContainerClick"),this.addEvent(this.$dropboxCloseButton,"click","onDropboxCloseButtonClick"),this.addEvent(this.$optionsContainer,"scroll","onOptionsScroll"),this.addEvent(this.$options,"click","onOptionsClick"),this.addEvent(this.$options,"mouseover","onOptionsMouseOver"),this.addEvent(this.$options,"touchmove","onOptionsTouchMove"),l.registerInstance(this)}addEvent(e,i,o,n=!1){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{const i=`${o}-${t}`;let r=this.events[i];r||(r=this[o].bind(this),this.events[i]=r),s.addEvent(e,t,r,n)})}removeEvents(){this.removeEvent(document,"click","onDocumentClick",!0),this.removeEvent(this.$allWrappers,"keydown","onKeyDown"),this.removeEvent(this.$toggleButton,"click keydown","onToggleButtonPress"),this.removeEvent(this.$clearButton,"click keydown","onClearButtonClick"),this.removeEvent(this.$dropboxContainer,"click","onDropboxContainerClick"),this.removeEvent(this.$dropboxCloseButton,"click","onDropboxCloseButtonClick"),this.removeEvent(this.$optionsContainer,"scroll","onOptionsScroll"),this.removeEvent(this.$options,"click","onOptionsClick"),this.removeEvent(this.$options,"mouseover","onOptionsMouseOver"),this.removeEvent(this.$options,"touchmove","onOptionsTouchMove"),this.$searchInput&&(this.removeEvent(this.$searchInput,"input","onSearch"),this.removeEvent(this.$searchInput,"change","preventPropagation"),this.$searchClear&&(this.removeEvent(this.$searchClear,"click","onSearchClear"),this.removeEvent(this.$searchClear,"keydown","onSearchClear"))),this.$toggleAllButton&&this.removeEvent(this.$toggleAllButton,"click","onToggleAllOptions"),this.$dropboxContainerBottom&&this.removeEvent(this.$dropboxContainerBottom,"focus","onDropboxContainerTopOrBottomFocus"),this.$dropboxContainerTop&&this.removeEvent(this.$dropboxContainerTop,"focus","onDropboxContainerTopOrBottomFocus")}removeEvent(e,i,o,n=!1){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{const i=`${o}-${t}`,r=this.events[i];r&&s.removeEvent(e,t,r,n)})}onDocumentClick(e){const t=e.target.closest(".vscomp-wrapper");if(!t)return void l.openInstances.forEach(e=>{const t=e;t.shouldFocusWrapperOnClose=!1,t.closeDropbox()});const s=t.parentElement.virtualSelect;s&&s!==this&&this.isOpened()&&!this.keepAlwaysOpen&&(this.shouldFocusWrapperOnClose=!1,this.closeDropbox())}onKeyDown(e){const t=e.which||e.keyCode,s=i[t];if(document.activeElement!==this.$searchInput||e.shiftKey||9!==t||this.multiple||(e.preventDefault(),this.focusFirstVisibleOption()),document.activeElement===this.$toggleAllButton&&(13===t||32===t))return e.preventDefault(),void this.toggleAllOptions();if(27===t||"Escape"===e.key){const e=this.hasDropboxWrapper&&!this.showAsPopup?this.$dropboxWrapper:this.$wrapper;if(e&&(document.activeElement===e||e.contains(document.activeElement))&&!this.keepAlwaysOpen)return void this.closeDropbox()}s&&this[s](e)}onEnterPress(e){e.preventDefault(),this.isOpened()?this.selectFocusedOption():!1===this.$ele.disabled&&this.openDropbox()}navigateOptions(e,t){e.preventDefault(),this.isOpened()?this.focusOption({direction:t}):this.openDropbox()}onDownArrowPress(e){this.navigateOptions(e,"next")}onUpArrowPress(e){this.navigateOptions(e,"previous")}onBackspaceOrDeletePress(e){e.target===this.$wrapper&&(e.preventDefault(),this.selectedValues.length>0&&this.reset())}onToggleButtonPress(e){if("keydown"===e.type){if("Enter"!==e.code&&"Space"!==e.code)return;e.preventDefault()}const t=e.target;if(t.closest(".vscomp-value-tag-clear-button"))return e.stopPropagation(),void this.removeValue(t.closest(".vscomp-value-tag"));t.closest(".toggle-button-child")||this.toggleDropbox()}onClearButtonClick(e){"click"===e.type?this.reset():"keydown"!==e.type||"Enter"!==e.code&&"Space"!==e.code||(e.stopPropagation(),this.reset())}onOptionsScroll(){this.scrollAnimationFrame||(this.scrollAnimationFrame=requestAnimationFrame(()=>{this.scrollAnimationFrame=null,this.isDestroyed||this.setVisibleOptions(!0)}))}onOptionsClick(e){const t=e.target.closest(".vscomp-option");t&&!s.hasClass(t,"disabled")&&(s.hasClass(t,"group-title")?this.onGroupTitleClick(t):this.selectOption(t,{event:e}))}onGroupTitleClick(e){if(!e||!this.multiple||this.disableOptionGroupCheckbox)return;const t=!s.hasClass(e,"selected");this.toggleGroupTitleCheckbox(e,t),this.toggleGroupOptions(e,t)}onDropboxContainerClick(e){e.target.closest(".vscomp-dropbox")||this.closeDropbox()}onDropboxCloseButtonClick(){this.closeDropbox()}onOptionsMouseOver(e){const t=e.target.closest(".vscomp-option");t&&this.isOpened()&&(this.shouldSkipOptionInNavigation(t)?this.removeOptionFocus():this.focusOption({$option:t}))}onOptionsTouchMove(){this.removeOptionFocus()}onSearch(e){e.stopPropagation(),this.setSearchValue(e.target.value,!0)}preventPropagation(e){e.stopPropagation()}onSearchClear(e){e.stopPropagation(),"Enter"!==e.code&&"Space"!==e.code&&"click"!==e.type||(this.setSearchValue(""),this.focusSearchInput())}onToggleAllOptions(){this.toggleAllOptions()}onDropboxContainerTopOrBottomFocus(){this.closeDropbox()}onResize(){this.setOptionsContainerHeight(!0)}static observeDomChanges(){l.domObserver||(l.domObserver=new MutationObserver(e=>{e.forEach(e=>{e.removedNodes.forEach(e=>{if(e.nodeType!==Node.ELEMENT_NODE)return;const t=e.classList.contains("vscomp-ele")?[e]:[];e.querySelectorAll(".vscomp-ele").forEach(e=>t.push(e)),t.forEach(e=>{!e.isConnected&&e.virtualSelect&&e.virtualSelect.destroy()})})})}),l.domObserver.observe(document.documentElement,{childList:!0,subtree:!0}))}static disconnectDomObserver(){l.domObserver&&(l.domObserver.disconnect(),l.domObserver=null)}static addGlobalListeners(){l.hasGlobalListeners||(document.addEventListener("reset",l.onFormReset),document.addEventListener("submit",l.onFormSubmit),window.addEventListener("resize",l.onResizeThrottled),l.hasGlobalListeners=!0)}static removeGlobalListeners(){l.hasGlobalListeners&&(document.removeEventListener("reset",l.onFormReset),document.removeEventListener("submit",l.onFormSubmit),window.removeEventListener("resize",l.onResizeThrottled),l.onResizeThrottled&&"function"==typeof l.onResizeThrottled.cancel&&l.onResizeThrottled.cancel(),l.hasGlobalListeners=!1)}static registerInstance(e){l.activeInstances.add(e),l.addGlobalListeners(),l.observeDomChanges()}static unregisterInstance(e){l.activeInstances.delete(e),0===l.activeInstances.size&&(l.removeGlobalListeners(),l.disconnectDomObserver())}beforeValueSet(e){this.toggleAllOptionsClass(!e&&void 0)}beforeSelectNewValue(e){const t=this.getNewOption();if(t){const e=t.index;this.newValues.push(t.value),this.setOptionProp(e,"isCurrentNew",!1),this.setOptionProp(e,"isNew",!0)}else e&&(this.setNewOption(e),this.toggleSelectedProp(this.lastOptionIndex,!0));this.setManagedTimeout(()=>{this.setSearchValue(""),this.focusSearchInput()},0)}afterRenderWrapper(){s.addClass(this.$ele,"vscomp-ele"),this.renderSearch(),this.setEleStyles(),this.setDropboxStyles(),this.setVisibleOptionsCount(),this.setOptionsContainerHeight(),this.addEvents();try{this.setEleProps(),this.keepAlwaysOpen||this.showAsPopup||this.initDropboxPopover(),this.initialSelectedValue?this.setValueMethod(this.initialSelectedValue,this.silentInitialValueSet):this.autoSelectFirstOption&&this.visibleOptions.length&&this.setValueMethod(this.visibleOptions[0].value,this.silentInitialValueSet),this.showOptionsOnlyOnSearch&&this.setSearchValue("",!1,!0),this.initialDisabled&&this.disable(),this.autofocus&&this.focus(),this.isInitialized=!0}catch(e){throw this.destroy(),e}}afterRenderOptions(){const e=this.getVisibleOptions(),t=!this.options.length&&!this.hasServerSearch,i=!t&&!e.length;(!this.allowNewOption||this.hasServerSearch||this.showOptionsOnlyOnSearch)&&(s.toggleClass(this.$allWrappers,"has-no-search-results",i),i?(s.setAttr(this.$noSearchResults,"tabindex","0"),s.setAttr(this.$noSearchResults,"aria-hidden","false")):(s.setAttr(this.$noSearchResults,"tabindex","-1"),s.setAttr(this.$noSearchResults,"aria-hidden","true"))),s.toggleClass(this.$allWrappers,"has-no-options",t),t?(s.setAttr(this.$noOptions,"tabindex","0"),s.setAttr(this.$noOptions,"aria-hidden","false")):(s.setAttr(this.$noOptions,"tabindex","-1"),s.setAttr(this.$noOptions,"aria-hidden","true")),this.setOptionAttr(),this.setOptionsPosition(),this.setOptionsTooltip(),document.activeElement!==this.$searchInput&&this.setManagedTimeout(()=>{const e=s.getElementsBySelector(".focused",this.$dropboxContainer)[0];void 0!==e&&e.focus({preventScroll:!0})},20)}afterSetOptionsContainerHeight(e){e&&this.showAsPopup&&this.setVisibleOptions()}afterSetSearchValue(){this.hasServerSearch?(clearTimeout(this.serverSearchTimeout),this.isSilentServerSearch=!1,this.serverSearchTimeout=setTimeout(()=>{this.serverSearch()},this.searchDelay)):this.setVisibleOptionsCount(),this.selectAllOnlyVisible&&this.toggleAllOptionsClass(),this.isClosing||this.focusOption({focusFirst:!0}),this.hasServerSearch||this.announceSearchResults()}afterSetVisibleOptionsCount(){this.scrollToTop(),this.setOptionsHeight(),this.setVisibleOptions(),this.updatePosition()}afterValueSet(){this.scrollToTop(),this.setSearchValue(""),this.renderOptions()}afterSetOptions(e){if(e&&this.setSelectedProp(),this.setOptionsHeight(),this.setVisibleOptions(),this.showOptionsOnlyOnSearch&&this.setSearchValue("",!1,!0),!e){this.isRefreshingOptions=!0;try{this.reset()}finally{this.isRefreshingOptions=!1}}}setProps(e){const s=this.setDefaultProps(e);this.setPropsFromElementAttr(s);const{convertToBoolean:i}=t;this.$ele=s.ele,this.dropboxWrapper=s.dropboxWrapper,this.valueKey=s.valueKey,this.labelKey=s.labelKey,this.descriptionKey=s.descriptionKey,this.aliasKey=s.aliasKey,this.optionHeightText=s.optionHeight,this.optionHeight=parseFloat(this.optionHeightText),this.multiple=i(s.multiple),this.hasSearch=i(s.search),this.searchByStartsWith=i(s.searchByStartsWith),this.searchGroup=i(s.searchGroup),this.hideClearButton=i(s.hideClearButton),this.autoSelectFirstOption=i(s.autoSelectFirstOption),this.hasOptionDescription=i(s.hasOptionDescription),this.silentInitialValueSet=i(s.silentInitialValueSet),this.allowNewOption=i(s.allowNewOption),this.markSearchResults=i(s.markSearchResults),this.showSelectedOptionsFirst=i(s.showSelectedOptionsFirst),this.disableSelectAll=i(s.disableSelectAll),this.keepAlwaysOpen=i(s.keepAlwaysOpen),this.showDropboxAsPopup=i(s.showDropboxAsPopup),this.hideValueTooltipOnSelectAll=i(s.hideValueTooltipOnSelectAll),this.showOptionsOnlyOnSearch=i(s.showOptionsOnlyOnSearch),this.selectAllOnlyVisible=i(s.selectAllOnlyVisible),this.alwaysShowSelectedOptionsCount=i(s.alwaysShowSelectedOptionsCount),this.alwaysShowSelectedOptionsLabel=i(s.alwaysShowSelectedOptionsLabel),this.disableAllOptionsSelectedText=i(s.disableAllOptionsSelectedText),this.showValueAsTags=i(s.showValueAsTags),this.disableOptionGroupCheckbox=i(s.disableOptionGroupCheckbox),this.enableSecureText=i(s.enableSecureText),this.showSecureTextWarning=i(s.showSecureTextWarning,!0),this.setValueAsArray=i(s.setValueAsArray),this.disableValidation=i(s.disableValidation),this.initialDisabled=i(s.disabled),this.required=i(s.required),this.autofocus=i(s.autofocus),this.useGroupValue=i(s.useGroupValue),this.focusSelectedOptionOnOpen=i(s.focusSelectedOptionOnOpen),this.noOptionsText=s.noOptionsText,this.noSearchResultsText=s.noSearchResultsText,this.selectAllText=s.selectAllText,this.searchNormalize=s.searchNormalize,this.searchPlaceholderText=s.searchPlaceholderText,this.searchFormLabel=s.searchFormLabel,this.optionsSelectedText=s.optionsSelectedText,this.optionSelectedText=s.optionSelectedText,this.allOptionsSelectedText=s.allOptionsSelectedText,this.searchResultsText=s.searchResultsText,this.searchResultText=s.searchResultText,this.noOptionsSelectedText=s.noOptionsSelectedText,this.selectedText=s.selectedText,this.loadingText=s.loadingText,this.requiredErrorText=s.requiredErrorText,this.minValuesErrorText=s.minValuesErrorText,this.clearButtonText=s.clearButtonText,this.moreText=s.moreText,this.placeholder=s.placeholder,this.position=s.position,this.textDirection=s.textDirection,this.dropboxWidth=s.dropboxWidth,this.tooltipFontSize=s.tooltipFontSize,this.tooltipAlignment=s.tooltipAlignment,this.tooltipMaxWidth=s.tooltipMaxWidth,this.updatePositionThrottle=s.updatePositionThrottle,this.noOfDisplayValues=parseInt(s.noOfDisplayValues,10),this.zIndex=parseInt(s.zIndex,10),this.maxValues=parseInt(s.maxValues,10),this.minValues=parseInt(s.minValues,10),this.name=s.name,this.additionalClasses=s.additionalClasses,this.additionalDropboxClasses=s.additionalDropboxClasses,this.additionalDropboxContainerClasses=s.additionalDropboxContainerClasses,this.additionalToggleButtonClasses=s.additionalToggleButtonClasses,this.popupDropboxBreakpoint=s.popupDropboxBreakpoint,this.popupPosition=s.popupPosition,this.onServerSearch=s.onServerSearch,this.labelRenderer=s.labelRenderer,this.selectedLabelRenderer=s.selectedLabelRenderer,this.initialSelectedValue=0===s.selectedValue?"0":s.selectedValue,this.emptyValue=s.emptyValue,this.ariaLabelText=s.ariaLabelText,this.ariaLabelledby=s.ariaLabelledby,this.ariaLabelClearButtonText=s.ariaLabelClearButtonText,this.ariaLabelTagClearButtonText=s.ariaLabelTagClearButtonText,this.ariaLabelSearchClearButtonText=s.ariaLabelSearchClearButtonText,this.maxWidth=s.maxWidth,this.searchDelay=s.searchDelay,this.showDuration=parseInt(s.showDuration,10),this.hideDuration=parseInt(s.hideDuration,10),t.prefersReducedMotion()&&(this.showDuration=0,this.hideDuration=0),this.selectedValues=[],this.selectedOptions=[],this.newValues=[],this.events={},this.tooltipEnterDelay=200,this.searchValue="",this.searchValueOriginal="",this.isAllSelected=!1,(void 0===s.search&&this.multiple||this.allowNewOption||this.showOptionsOnlyOnSearch)&&(this.hasSearch=!0),this.hasServerSearch="function"==typeof this.onServerSearch,(this.maxValues||this.hasServerSearch||this.showOptionsOnlyOnSearch)&&(this.disableSelectAll=!0,this.disableOptionGroupCheckbox=!0),this.keepAlwaysOpen&&(this.dropboxWrapper="self"),this.showAsPopup=this.showDropboxAsPopup&&!this.keepAlwaysOpen&&window.innerWidth<=parseFloat(this.popupDropboxBreakpoint),this.hasSearchContainer=this.hasSearch||this.multiple&&!this.disableSelectAll,this.optionsCount=this.getOptionsCount(s.optionsCount),this.halfOptionsCount=Math.ceil(this.optionsCount/2),this.optionsHeight=this.getOptionsHeight(),this.uniqueId=this.getUniqueId(),this.shouldFocusWrapperOnClose=!0,this.isClosing=!1,this.isSilentServerSearch=!1,this.ariaSetSize=0,this.ariaMetadataDirty=!0}setDefaultProps(e){const t=l.globalDefaults,s=s=>void 0!==e[s]?e[s]:t[s],i={dropboxWrapper:"self",valueKey:"value",labelKey:"label",descriptionKey:"description",aliasKey:"alias",ariaLabelText:"Options list",ariaLabelClearButtonText:"Clear button",ariaLabelTagClearButtonText:"Remove option",ariaLabelSearchClearButtonText:"Clear search input",optionsCount:5,noOfDisplayValues:50,optionHeight:"40px",noOptionsText:"No options found",noSearchResultsText:"No results found",selectAllText:"Select All",searchNormalize:!1,searchPlaceholderText:"Search...",searchFormLabel:"Search",clearButtonText:"Clear",moreText:"more...",optionsSelectedText:"options selected",optionSelectedText:"option selected",searchResultsText:"results available",searchResultText:"result available",noOptionsSelectedText:"No options selected",selectedText:"selected",loadingText:"Loading results",requiredErrorText:"This field is required",minValuesErrorText:"Select at least {count} options",allOptionsSelectedText:"All",placeholder:"Select",position:"bottom left",zIndex:s("keepAlwaysOpen")?1:2,tooltipFontSize:"14px",tooltipAlignment:"center",tooltipMaxWidth:"300px",updatePositionThrottle:100,name:"",additionalClasses:"",additionalDropboxClasses:"",additionalDropboxContainerClasses:"",additionalToggleButtonClasses:"",maxValues:0,showDropboxAsPopup:!0,showSecureTextWarning:!0,popupDropboxBreakpoint:"576px",popupPosition:"center",hideValueTooltipOnSelectAll:!0,emptyValue:"",searchDelay:300,focusSelectedOptionOnOpen:!0,showDuration:300,hideDuration:200};s("hasOptionDescription")&&(i.optionsCount=4,i.optionHeight="50px");const o=e=>{const t={};return Object.keys(e||{}).forEach(s=>{void 0!==e[s]&&(t[s]=e[s])}),t};return Object.assign(i,o(t),o(e))}setPropsFromElementAttr(e){const t=e.ele;Object.keys(r).forEach(s=>{let i=t.getAttribute(s);-1===o.indexOf(s)||""!==i&&"true"!==i||(i=!0),i&&(e[r[s]]=i)})}setEleProps(){const{$ele:e}=this;e.virtualSelect=this,e.value=this.multiple?[]:"",e.name=this.name,e.disabled=!1,e.required=this.required,s.toggleAria(this.$allWrappers,"required",this.required),e.autofocus=this.autofocus,e.multiple=this.multiple,e.form=e.closest("form"),e.reset=l.reset,e.setValue=l.setValueMethod,e.setOptions=l.setOptionsMethod,e.setDisabledOptions=l.setDisabledOptionsMethod,e.setEnabledOptions=l.setEnabledOptionsMethod,e.toggleSelectAll=l.toggleSelectAll,e.isAllSelected=l.isAllSelected,e.addOption=l.addOptionMethod,e.getNewValue=l.getNewValueMethod,e.getDisplayValue=l.getDisplayValueMethod,e.getSelectedOptions=l.getSelectedOptionsMethod,e.getDisabledOptions=l.getDisabledOptionsMethod,e.open=l.openMethod,e.close=l.closeMethod,e.focus=l.focusMethod,e.enable=l.enableMethod,e.disable=l.disableMethod,e.destroy=l.destroyMethod,e.validate=l.validateMethod,e.toggleRequired=l.toggleRequiredMethod,this.hasDropboxWrapper&&(this.$dropboxWrapper.virtualSelect=this)}setValueMethod(e,s){const i=Object.create(null),o=Object.create(null);let n=[];const r=this.multiple;let a=t.normalizeValues(e);if(a){if(Array.isArray(a)||(a=[a]),r){const{maxValues:e}=this;e&&a.length>e&&a.splice(e)}else a.length>1&&(a=[a[0]]);this.useGroupValue&&(a=this.setGroupOptionsValue(a)),a.forEach((e,t)=>{i[e]=!0,o[e]=t}),this.allowNewOption&&a&&this.setNewOptionsFromValue(a)}this.options.forEach(e=>{const s=t.normalizeValues(e.value);!0!==i[s]||e.isDisabled||e.isGroupTitle?e.isSelected=!1:(e.isSelected=!0,n.push(e.value))}),r?(this.hasOptionGroup&&this.setGroupsSelectedProp(),n.sort((e,s)=>o[t.normalizeValues(e)]-o[t.normalizeValues(s)])):[n]=n,this.beforeValueSet(),this.setValue(n,{disableEvent:s}),this.afterValueSet()}setGroupOptionsValue(e){const t=[],s={},i=Object.create(null);return e.forEach(e=>{i[e]=!0}),this.options.forEach(e=>{const{value:o}=e,n=!0===i[o];e.isGroupTitle?n&&(s[e.index]=!0):(n||s[e.groupIndex])&&t.push(o)}),t}setGroupsSelectedProp(){const e=this.isAllGroupOptionsSelected.bind(this);this.options.forEach(t=>{t.isGroupTitle&&(t.isSelected=e(t.index))})}setOptionsMethod(e,t){this.setOptions(e),this.afterSetOptions(t)}setDisabledOptionsMethod(e,t=!1){this.setDisabledOptions(e,!0),t||(this.setValueMethod(null),this.toggleAllOptionsClass()),this.setVisibleOptions()}setDisabledOptions(e,t=!1){let s=[];if(e)if(!0===e)t&&this.options.forEach(e=>(e.isDisabled=!0,s.push(e.value),e));else{s=e.map(e=>e.toString());const i=Object.create(null);s.forEach(e=>{i[e]=!0}),t&&this.options.forEach(e=>(e.isDisabled=!0===i[e.value],e))}else t&&this.options.forEach(e=>(e.isDisabled=!1,e));this.disabledOptions=s}setEnabledOptionsMethod(e,t=!1){this.setEnabledOptions(e),t||(this.setValueMethod(null),this.toggleAllOptionsClass()),this.setVisibleOptions()}setEnabledOptions(e){if(void 0===e)return;const t=[];if(!0===e)this.options.forEach(e=>(e.isDisabled=!1,e));else{const s=Object.create(null);e.forEach(e=>{s[e]=!0}),this.options.forEach(e=>{const i=!0!==s[e.value];return e.isDisabled=i,i&&t.push(e.value),e})}this.disabledOptions=t}setOptions(e=[]){const s=[],i=this.disabledOptions.length,{valueKey:o,labelKey:n,descriptionKey:r,aliasKey:a,hasOptionDescription:l}=this,{getString:h,convertToBoolean:p}=t,c=this.secureText.bind(this),u=this.getAlias.bind(this);let d=0,v=!1;const b=Object.create(null);let m=!1;this.disabledOptions.forEach(e=>{b[e]=!0});const g=e=>{"object"!=typeof e&&(e={[o]:e,[n]:e});const f=h(e[o]),x=h(e[n]),S=f,O=c(x),y=e.options,$=!!y,w={index:d,value:S,valueNormalized:S.toLowerCase(),label:O,labelNormalized:this.searchNormalize&&""!==x.trim()?t.normalizeString(x).toLowerCase():x.toLowerCase(),alias:u(e[a]),isVisible:p(e.isVisible,!0),isNew:e.isNew||!1,isGroupTitle:$,classNames:e.classNames};if(m||""!==S||(m=!0),i&&(w.isDisabled=!0===b[S]),e.isGroupOption&&(w.isGroupOption=!0,w.groupIndex=e.groupIndex),l){const s=h(e[r]);w.description=c(s),w.descriptionNormalized=this.searchNormalize&&""!==s.trim()?t.normalizeString(s).toLowerCase():s.toLowerCase()}if(e.customData&&(w.customData=e.customData),s.push(w),d+=1,$){const e=w.index;v=!0,y.forEach(t=>{t.isGroupOption=!0,t.groupIndex=e,g(t)})}};Array.isArray(e)&&e.forEach(g);const f=s.length,{$ele:x}=this;x.options=s,x.length=f,this.options=s,this.visibleOptionsCount=f,this.lastOptionIndex=f-1,this.newValues=[],this.hasOptionGroup=v,this.hasEmptyValueOption=m,this.setSortedOptions()}setServerOptions(e=[]){this.setOptionsMethod(e,!0);const{selectedOptions:t}=this,i=this.options;let o=!1;if(t.length){const e=Object.create(null);o=!0,i.forEach(t=>{e[t.value]=!0}),t.forEach(t=>{!0!==e[t.value]&&(t.isVisible=!1,i.push(t))}),this.setOptionsMethod(i,!0)}this.allowNewOption&&this.searchValue&&(i.some(e=>e.label.toLowerCase()===this.searchValue)||(o=!0,this.setNewOption())),o?(this.setVisibleOptionsCount(),this.multiple&&this.toggleAllOptionsClass(),this.setValueText()):this.updatePosition(),this.setVisibleOptionsCount(),s.removeClass(this.$allWrappers,"server-searching"),this.isInitialized&&!this.isSilentServerSearch&&this.isOpened()&&this.announce(this.getResultsCountMessage())}setSelectedOptions(){this.selectedOptions=this.options.filter(e=>e.isSelected)}setSortedOptions(){this.ariaMetadataDirty=!0;let e=[...this.options];this.showSelectedOptionsFirst&&this.selectedValues.length&&(e=this.hasOptionGroup?this.sortOptionsGroup(e):this.sortOptions(e)),this.sortedOptions=e}setVisibleOptions(){let e=[...this.sortedOptions];const t=2*this.optionsCount,s=this.getVisibleStartIndex(),i=this.getNewOption(),o=s+t-1;let n=0;i&&(i.visibleIndex=n,n+=1),e=e.filter(e=>{let t=!1;return e.isVisible&&!e.isCurrentNew&&(t=n>=s&&n<=o,e.visibleIndex=n,n+=1),t}),i&&(e=[i,...e]),this.visibleOptions=e,this.visibleOptionsCount=e.length,this.renderOptions()}setOptionsPosition(e){const t=parseInt((e||this.getVisibleStartIndex())*this.optionHeight,10);this.$options.style.transform=`translate3d(0, ${t}px, 0)`,s.setData(this.$options,"top",t)}setOptionsTooltip(){const e=this.getVisibleOptions(),{hasOptionDescription:t}=this;e.forEach(e=>{const i=this.$dropboxContainer.querySelector(`.vscomp-option[data-index="${e.index}"]`);s.setData(i.querySelector(".vscomp-option-text"),"tooltip",e.label),t&&s.setData(i.querySelector(".vscomp-option-description"),"tooltip",e.description)})}setValue(e,{disableEvent:i=!1,disableValidation:o=!1}={}){const n=t.normalizeValues(e);this.hasEmptyValueOption&&""===n||n?Array.isArray(n)?this.selectedValues=[...n]:this.selectedValues=[n]:this.selectedValues=[];const r=this.getValue();this.$ele.value=r,this.$hiddenInput.value=this.getInputValue(r),this.isMaxValuesSelected=!!(this.maxValues&&this.maxValues<=this.selectedValues.length),this.toggleAllOptionsClass(),this.setValueText();const a=t.isNotEmpty(this.selectedValues);s.toggleClass(this.$allWrappers,"has-value",a),s.toggleClass(this.$allWrappers,"max-value-selected",this.isMaxValuesSelected),s.setAttr(this.$clearButton,"tabindex",a?"0":"-1"),s.setAria(this.$clearButton,"hidden",!1===a);let l=!0;o||(l=this.validate()),this.isInitialized&&l&&this.announce(this.getSelectionMessage()),i||s.dispatchEvent(this.$ele,"change",!0)}setValueText(){const{multiple:e,selectedValues:i,noOfDisplayValues:o,showValueAsTags:n,$valueText:r,selectedLabelRenderer:a}=this,l=[];let h=[];const p=i.length;let c=0;const u=this.isAllSelected&&!this.hasServerSearch&&!this.disableAllOptionsSelectedText&&!n;if(u&&this.hideValueTooltipOnSelectAll)r.innerHTML=`${this.allOptionsSelectedText} (${p})`;else{this.getSelectedOptions({fullDetails:!0,keepSelectionOrder:!0}).some(e=>{if(e.isCurrentNew)return!1;if(c>=o)return!0;let{label:s}=e;if("function"==typeof a&&(s=a(e)),l.push(s),c+=1,n){const i=this.getTooltipAttrText(s,!0,!0);let o="";this.ariaLabelTagClearButtonText&&(o=`aria-label="${t.getAriaLabelText(s)}, ${t.getAriaLabelText(this.ariaLabelTagClearButtonText)}"`);const n=`\n ${s}\n \n \n \n `;h.push(n)}else h.push(s);return!1});const i=p-o;i>0&&h.push(`+ ${i} ${this.moreText}`);const d=l.join(", ");if(""===d)r.innerHTML=this.placeholder;else if(r.innerHTML=d,e){const{maxValues:e}=this;if(this.alwaysShowSelectedOptionsCount||s.hasEllipsis(r)||e||n){let t=`${p}`;if(e&&(t+=` / ${e}`),u)r.innerHTML=`${this.allOptionsSelectedText} (${p})`;else if(n)r.innerHTML=h.join(""),this.$valueTags=r.querySelectorAll(".vscomp-value-tag"),this.setValueTagAttr();else if(!this.alwaysShowSelectedOptionsLabel){const e=1===p?this.optionSelectedText:this.optionsSelectedText;r.innerHTML=`${t} ${e}`}}else h=[]}}let d="";0===p?d=this.placeholder:n||(d=h.join(", ")),n||s.setData(r,"tooltip",d),e&&(n?this.updatePosition():s.setData(r,"tooltipEllipsisOnly",0===p))}setSearchValue(e,t=!1,i=!1){if(e===this.searchValueOriginal&&!i)return;t||(this.$searchInput.value=e);const o=e.replace(/\\/g,"").toLowerCase().trim();this.searchValue=o,this.searchValueOriginal=e,s.toggleClass(this.$allWrappers,"has-search-value",e),s.setAttr(this.$searchClear,"tabindex",""!==e?"0":"-1"),s.setAria(this.$searchClear,"hidden",""===e),this.afterSetSearchValue()}setVisibleOptionsCount(){let e,s=0,i=!1;const{searchGroup:o,showOptionsOnlyOnSearch:n,searchByStartsWith:r}=this;let{searchValue:a}=this;a=this.searchNormalize&&""!==a.trim()?t.normalizeString(a):a;const l=this.isOptionVisible.bind(this);this.hasOptionGroup&&(e=this.getVisibleOptionGroupsMapping(a)),this.options.forEach(t=>{if(t.isCurrentNew)return;let h;n&&!a?(t.isVisible=!1,h={isVisible:!1,hasExactOption:!1}):h=l({data:t,searchValue:a,hasExactOption:i,visibleOptionGroupsMapping:e,searchGroup:o,searchByStartsWith:r}),h.isVisible&&(s+=1),i||(i=h.hasExactOption)}),this.allowNewOption&&(a&&!i?(this.setNewOption(),s+=1):this.removeNewOption()),this.visibleOptionsCount=s,this.filteredOptionsCount=s,this.ariaMetadataDirty=!0,this.afterSetVisibleOptionsCount()}calculateAriaMetadata(){let e=0,t=0;if((this.sortedOptions&&this.sortedOptions.length?this.sortedOptions:this.options).forEach(s=>{if(s.isCurrentNew)s.filteredIndex=void 0;else if(!0===s.isVisible){const i=s.isGroupTitle&&this.multiple&&!this.disableOptionGroupCheckbox;!s.isGroupTitle||i?(t+=1,e+=1,s.filteredIndex=t):s.filteredIndex=void 0}else s.filteredIndex=void 0}),this.allowNewOption){const s=this.getNewOption();s&&!0===s.isVisible?(t+=1,e+=1,s.filteredIndex=t):s&&(s.filteredIndex=void 0)}this.ariaSetSize=e}setOptionProp(e,t,s){this.options[e]&&(this.options[e][t]=s)}setOptionsHeight(){this.$optionsList.style.height=this.optionHeight*this.visibleOptionsCount+"px"}setOptionsContainerHeight(e){let t;e?this.showAsPopup&&(this.optionsCount=this.getOptionsCount(),this.halfOptionsCount=Math.ceil(this.optionsCount/2),t=this.getOptionsHeight(),this.optionsHeight=t):(t=this.optionsHeight,this.keepAlwaysOpen&&(s.setStyle(this.$noOptions,"height",t),s.setStyle(this.$noSearchResults,"height",t))),s.setStyle(this.$optionsContainer,"max-height",t),this.afterSetOptionsContainerHeight(e)}setNewOption(e){const t=e||this.searchValueOriginal.trim();if(!t)return;this.ariaMetadataDirty=!0;const s=this.getNewOption();if(s){const e=s.index;this.setOptionProp(e,"value",t),this.setOptionProp(e,"label",this.secureText(t))}else{const s={value:t,label:t};e?(s.isNew=!0,this.newValues.push(t)):s.isCurrentNew=!0,this.addOption(s)}}setSelectedProp(){const e=Object.create(null);this.selectedValues.forEach(t=>{e[t]=!0}),this.options.forEach(t=>{!0===e[t.value]&&(t.isSelected=!0)})}setNewOptionsFromValue(e){if(!e)return;const t=this.setNewOption.bind(this),s=Object.create(null);this.options.forEach(e=>{s[e.value]=!0}),e.forEach(e=>{e&&!0!==s[e]&&t(e)})}setDropboxWrapperWidth(){if(this.showAsPopup)return;const e=this.dropboxWidth||`${this.$wrapper.offsetWidth}px`;s.setStyle(this.$dropboxContainer,"max-width",e)}setEleStyles(){const{maxWidth:e}=this,t={};e&&(t["max-width"]=e),s.setStyles(this.$ele,t)}setDropboxStyles(){const{dropboxWidth:e}=this,t={},i={"z-index":this.zIndex};e&&(this.showAsPopup?t["max-width"]=e:i.width=e),s.setStyles(this.$dropboxContainer,i),s.setStyles(this.$dropbox,t)}setOptionAttr(){const{$visibleOptions:e}=this,{options:t}=this,i=`${this.optionHeight}px`,{setStyle:o,getData:n,setData:r}=s;e&&e.length&&e.forEach(e=>{const s=t[n(e,"index")];o(e,"height",i),r(e,"value",s.value)})}setValueTagAttr(){const{$valueTags:e}=this;if(!e||!e.length)return;const{getData:t,setData:i}=s,{options:o}=this;e.forEach(e=>{const s=t(e,"index");if(void 0!==s){const t=o[s];i(e,"value",t.value)}})}setScrollTop(){const{selectedValues:e}=this;if(this.showSelectedOptionsFirst||!this.focusSelectedOptionOnOpen||0===e.length)return;const t=Object.create(null);let s;e.forEach(e=>{t[e]=!0}),this.options.some(e=>!!t[e.value]&&(s=e.visibleIndex,!0)),s&&(this.$optionsContainer.scrollTop=this.optionHeight*s)}getVisibleOptions(){return this.visibleOptions||[]}getValue(){let e;return e=this.multiple?this.useGroupValue?this.getGroupValue():this.selectedValues:this.selectedValues[0]||"",t.normalizeValues(e)}getGroupValue(){const e=[],t={};return this.options.forEach(s=>{if(!s.isSelected)return;const{value:i}=s;s.isGroupTitle?i&&(t[s.index]=!0,e.push(i)):!0!==t[s.groupIndex]&&e.push(i)}),e}getInputValue(e){let t=e;return t&&t.length?this.setValueAsArray&&this.multiple&&(t=JSON.stringify(t)):t=this.emptyValue,t}getFirstVisibleOptionIndex(){return Math.ceil(this.$optionsContainer.scrollTop/this.optionHeight)}getVisibleStartIndex(){let e=this.getFirstVisibleOptionIndex()-this.halfOptionsCount;return e<0&&(e=0),e}getTooltipAttrText(e,t=!1,i=!1){const o={"data-tooltip":e||"","data-tooltip-enter-delay":this.tooltipEnterDelay,"data-tooltip-z-index":this.zIndex,"data-tooltip-font-size":this.tooltipFontSize,"data-tooltip-alignment":this.tooltipAlignment,"data-tooltip-max-width":this.tooltipMaxWidth,"data-tooltip-ellipsis-only":t,"data-tooltip-allow-html":i};return s.getAttributesText(o)}getOptionObj(e){if(!e)return;const{getString:s}=t,i=this.secureText.bind(this),o=s(e.value),n=s(e.label),r=s(e.description);return{index:e.index,value:o,valueNormalized:o.toLowerCase(),label:i(n),labelNormalized:this.searchNormalize&&""!==n.trim()?t.normalizeString(n).toLowerCase():n.toLowerCase(),description:i(r),descriptionNormalized:this.searchNormalize&&""!==r.trim()?t.normalizeString(r).toLowerCase():r.toLowerCase(),alias:this.getAlias(e.alias),isCurrentNew:e.isCurrentNew||!1,isNew:e.isNew||!1,isVisible:!0}}getNewOption(){const e=this.options[this.lastOptionIndex];if(e&&e.isCurrentNew)return e}getOptionIndex(e){let t;return this.options.some(s=>s.value===e&&(t=s.index,!0)),t}getNewValue(){const e=Object.create(null);this.newValues.forEach(t=>{e[t]=!0});const t=this.selectedValues.filter(t=>!0===e[t]);return this.multiple?t:t[0]}getAlias(e){let t=e;return t&&(t=Array.isArray(t)?t.join(","):t.toString().trim(),t=t.toLowerCase()),t||""}getDisplayValue(){const e=[];return this.options.forEach(t=>{t.isSelected&&e.push(t.label)}),this.multiple?e:e[0]||""}getSelectedOptions({fullDetails:e=!1,keepSelectionOrder:t=!1}={}){const{valueKey:s,labelKey:i,selectedValues:o}=this,n=[];if(this.options.forEach(t=>{if(t.isSelected&&!t.isGroupTitle)if(e)n.push(t);else{const e={[s]:t.value,[i]:t.label};t.isNew&&(e.isNew=!0),t.customData&&(e.customData=t.customData),n.push(e)}}),t){const e=Object.create(null);o.forEach((t,s)=>{e[t]=s}),n.sort((t,s)=>e[t.value]-e[s.value])}return this.multiple||e?n:n[0]}getDisabledOptions(){const{valueKey:e,labelKey:t,disabledOptions:s}=this,i=Object.create(null),o=[];return s.forEach(e=>{i[e]=!0}),this.options.forEach(({value:s,label:n})=>{i[s]&&o.push({[e]:s,[t]:n})}),o}getVisibleOptionGroupsMapping(e){let{options:t}=this;const s={},i=this.isOptionVisible.bind(this);return t=this.structureOptionGroup(t),t.forEach(t=>{s[t.index]=t.options.some(t=>i({data:t,searchValue:e}).isVisible)}),s}getOptionsCount(e){let t;if(this.showAsPopup){let e=80*window.innerHeight/100-48;this.hasSearchContainer&&(e-=40),t=Math.floor(e/this.optionHeight)}else t=parseInt(e,10);return t}getOptionsHeight(){return this.optionsCount*this.optionHeight+"px"}isSelectableGroupTitle(e){return e&&s.hasClass(e,"group-title")&&this.multiple&&!this.disableOptionGroupCheckbox}shouldSkipOptionInNavigation(e){return!!e&&(!!s.hasClass(e,"disabled")||s.hasClass(e,"group-title")&&!this.isSelectableGroupTitle(e))}getSibling(e,t){const s="next"===t?"nextElementSibling":"previousElementSibling";let i=e;do{i&&(i=i[s])}while(this.shouldSkipOptionInNavigation(i));return i}getUniqueId(){const e=t.getRandomInt(1e4);return document.querySelector(`#vscomp-ele-wrapper-${e}`)?this.getUniqueId():e}initDropboxPopover(){const e={ele:this.$ele,target:this.$dropboxContainer,position:this.position,zIndex:this.zIndex,margin:4,transitionDistance:30,hideArrowIcon:!0,disableManualAction:!0,disableUpdatePosition:!this.hasDropboxWrapper,updatePositionThrottle:this.updatePositionThrottle,showDuration:this.showDuration,hideDuration:this.hideDuration,afterShow:this.afterShowPopper.bind(this),afterHide:this.afterHidePopper.bind(this)};this.dropboxPopover=new PopoverComponent(e)}openDropbox(e){l.lastInteractedInstance=this;let t="";e||(t=this.$dropboxContainer.style.transition,this.$dropboxContainer.style.transition="none"),this.isSilentOpen=e,l.openInstances.forEach(e=>{if(e!==this){const t=e;t.shouldFocusWrapperOnClose=!1,t.closeDropbox(!0)}}),l.openInstances.add(this),this.isSilentServerSearch=!1,s.setAttr(this.$dropboxWrapper,"tabindex","0"),s.setAria(this.$dropboxWrapper,"hidden",!1),s.setAttr(this.$dropboxContainerTop,"tabindex","0"),s.setAria(this.$dropboxContainerTop,"hidden",!1),s.setAttr(this.$dropboxContainerBottom,"tabindex","0"),s.setAria(this.$dropboxContainerBottom,"hidden",!1),e?s.setStyle(this.$dropboxContainer,"display","inline-flex"):(s.dispatchEvent(this.$ele,"beforeOpen"),s.setAria(this.$wrapper,"expanded",!0)),this.setDropboxWrapperWidth(),s.removeClass(this.$allWrappers,"closed"),s.changeTabIndex(this.$allWrappers,0),e||(this.$dropboxContainer.offsetHeight,this.$dropboxContainer.style.transition=t),this.dropboxPopover&&!e?this.dropboxPopover.show():this.afterShowPopper()}afterShowPopper(){const e=this.isSilentOpen;this.isSilentOpen=!1,e||(this.moveSelectedOptionsFirst(),this.setScrollTop(),s.addClass(this.$allWrappers,"focused"),this.showAsPopup?(s.addClass(this.$body,"vscomp-popup-active"),this.isPopupActive=!0):this.focusElementOnOpen(),s.dispatchEvent(this.$ele,"afterOpen"))}closeDropbox(e){if(this.isSilentClose=e,l.openInstances.delete(this),!1===this.isOpened())return;if(this.keepAlwaysOpen)return void this.removeOptionFocus();const t=document.activeElement,i=t&&this.$wrapper.contains(t)||this.hasDropboxWrapper&&t&&this.$dropboxWrapper.contains(t);this.shouldFocusWrapperOnClose&&l.lastInteractedInstance===this&&!e&&(null===t||t===document.body||i)&&this.$wrapper.focus(),e?s.setStyle(this.$dropboxContainer,"display",""):(s.dispatchEvent(this.$ele,"beforeClose"),s.setAria(this.$wrapper,"expanded",!1),this.removeOptionFocus(),this.setActiveDescendant("")),this.dropboxPopover&&!e?(this.dropboxPopover.hide(),s.setAttr(this.$dropboxWrapper,"tabindex","-1"),s.setAria(this.$dropboxWrapper,"hidden",!0),s.setAttr(this.$dropboxContainerTop,"tabindex","-1"),s.setAria(this.$dropboxContainerTop,"hidden",!0),s.setAttr(this.$dropboxContainerBottom,"tabindex","-1"),s.setAria(this.$dropboxContainerBottom,"hidden",!0)):this.afterHidePopper(),this.isClosing=!0;try{this.setSearchValue("")}finally{this.isClosing=!1}this.hasServerSearch&&(this.isSilentServerSearch=!0)}afterHidePopper(){const e=this.isSilentClose;this.isSilentClose=!1,s.removeClass(this.$allWrappers,"focused"),this.removeOptionFocus(),!e&&this.isPopupActive&&(s.removeClass(this.$body,"vscomp-popup-active"),this.isPopupActive=!1),s.addClass(this.$allWrappers,"closed"),e||s.dispatchEvent(this.$ele,"afterClose"),this.shouldFocusWrapperOnClose=!0,s.setAttr(this.$dropboxWrapper,"tabindex","-1"),s.setAria(this.$dropboxWrapper,"hidden",!0),s.setAttr(this.$dropboxContainerTop,"tabindex","-1"),s.setAria(this.$dropboxContainerTop,"hidden",!0),s.setAttr(this.$dropboxContainerBottom,"tabindex","-1"),s.setAria(this.$dropboxContainerBottom,"hidden",!0)}moveSelectedOptionsFirst(){this.$optionsContainer.scrollTop&&this.selectedValues.length||this.setVisibleOptions(),this.showSelectedOptionsFirst&&(this.setSortedOptions(),this.scrollToTop(),this.setVisibleOptions())}toggleDropbox(){l.lastInteractedInstance=this,this.isOpened()?this.closeDropbox():this.openDropbox()}updatePosition(){this.dropboxPopover&&this.isOpened()&&this.$ele.updatePosition()}isOpened(){return!s.hasClass(this.$wrapper,"closed")}focusSearchInput(){const e=this.$searchInput;e&&e.focus()}focusElementOnOpen(){const e=this.$searchInput,t=!this.options.length&&!this.hasServerSearch;if(e)t&&!this.allowNewOption?(s.setAttr(e,"disabled",""),this.$noOptions.focus()):(e.removeAttribute("disabled"),e.focus());else{const e=this.$dropbox.querySelector('[tabindex="0"]');void 0!==s.getData(e,"index")?this.focusOption({direction:"next"}):e?e.focus():this.focusFirstVisibleOption()}}focusFirstVisibleOption(){let e=this.$optionsContainer.querySelector(`[data-index='${this.getFirstVisibleOptionIndex()}']`);e?(this.shouldSkipOptionInNavigation(e)&&(e=this.getSibling(e,"next")),e&&(s.setAttr(e,"tabindex","0"),this.$optionsContainer.scrollTop=this.optionHeight*this.getFirstVisibleOptionIndex(),this.focusOption({focusFirst:!0}),e.focus())):(e=this.$dropbox.querySelector('[tabindex="0"]'),e&&e.focus())}focusOption({direction:e,$option:t,focusFirst:i}={}){const o=this.$dropboxContainer.querySelector(".vscomp-option.focused");let n;if(t)n=t;else if(!o||i){const e=this.getFirstVisibleOptionIndex();n=this.$dropboxContainer.querySelector(`.vscomp-option[data-visible-index="${e}"]`),this.shouldSkipOptionInNavigation(n)&&(n=this.getSibling(n,"next"))}else n=this.getSibling(o,e);n&&n!==o&&(o&&this.toggleOptionFocusedState(o,!1),this.toggleOptionFocusedState(n,!0),this.toggleFocusedProp(s.getData(n,"index"),!0),this.moveFocusedOptionToView(n))}moveFocusedOptionToView(e){const t=e||this.$dropboxContainer.querySelector(".vscomp-option.focused");if(!t)return;let i;const o=this.$optionsContainer.getBoundingClientRect(),n=t.getBoundingClientRect(),r=o.top,a=o.bottom,l=o.height,h=n.top,p=n.bottom,c=n.height,u=t.offsetTop,d=s.getData(this.$options,"top","number");r>h?i=u+d:a{if(e.isDisabled||e.isGroupTitle||!e.isVisible||e.isSelected)return;const{index:t}=e;if(t>o&&t{e(parseInt(t,10))})}this.setManagedTimeout(()=>{this.renderOptions()},0)}toggleAllOptions(e){if(!this.multiple||this.disableSelectAll)return;const t="boolean"==typeof isSelected?e:!s.hasClass(this.$toggleAllCheckbox,"checked"),i=[],{selectAllOnlyVisible:o}=this;this.options.forEach(e=>{const s=e;if(s.isDisabled||s.isCurrentNew)return;const{isVisible:n,isSelected:r}=s;!t&&(!o||n||!r)||t&&o&&!n&&!r?s.isSelected=!1:(s.isSelected=!0,s.isGroupTitle||i.push(s.value))}),this.toggleAllOptionsClass(t),this.setValue(i),this.renderOptions()}toggleAllOptionsClass(e){if(!this.multiple)return;let t=!1;"boolean"==typeof e||(e=this.isAllOptionsSelected()),!e&&this.selectAllOnlyVisible&&""!==this.searchValue&&(this.visibleOptionsCount>0||""===this.searchValue)&&(t=this.isAllOptionsSelected(!0));const i=e||t;s.toggleClass(this.$toggleAllCheckbox,"checked",i),s.setAria(this.$toggleAllButton,"checked",i),this.isAllSelected=e}isAllOptionsSelected(e){let t=!1;return this.options.length&&this.selectedValues.length&&(t=!this.options.some(t=>!t.isSelected&&!t.isDisabled&&!t.isGroupTitle&&(!e||t.isVisible))),t}isAllGroupOptionsSelected(e){let t=!1;return this.options.length&&(t=!this.options.some(t=>!t.isSelected&&!t.isDisabled&&!t.isGroupTitle&&t.groupIndex===e)),t}toggleGroupOptionsParent(e,t){if(!this.hasOptionGroup||this.disableOptionGroupCheckbox||!e)return;let i=s.getData(e,"groupIndex");void 0!==i&&(i=parseInt(i,10));const o=this.$options.querySelector(`.vscomp-option[data-index="${i}"]`),n="boolean"==typeof t?t:this.isAllGroupOptionsSelected(i);this.toggleGroupTitleCheckbox(o,n),this.toggleGroupTitleProp(i,n)}toggleGroupTitleProp(e,t){const s="boolean"==typeof t?t:this.isAllGroupOptionsSelected(e);this.toggleSelectedProp(e,s)}toggleGroupOptions(e,i){if(!this.hasOptionGroup||this.disableOptionGroupCheckbox||!e)return;const o=s.getData(e,"index","number"),{selectedValues:n,selectAllOnlyVisible:r}=this,a=Object.create(null),{removeItemFromArray:l}=t;n.forEach(e=>{a[e]=!0}),this.options.forEach(e=>{if(e.isDisabled||e.groupIndex!==o)return;const{value:t}=e;!i||r&&!e.isVisible?(e.isSelected=!1,a[t]&&l(n,t)):(e.isSelected=!0,a[t]||n.push(t))}),this.toggleAllOptionsClass(!!i&&null),this.setValue(n),this.setManagedTimeout(()=>{this.renderOptions()},0)}toggleGroupTitleCheckbox(e,t){if(!e)return;const i=s.getData(e,"index","number");this.toggleSelectedProp(i,t),this.toggleOptionSelectedState(e,t)}toggleFocusedProp(e,t=!1){null!==this.focusedOptionIndex&&void 0!==this.focusedOptionIndex&&this.setOptionProp(this.focusedOptionIndex,"isFocused",!1),this.setOptionProp(e,"isFocused",t),this.focusedOptionIndex=e}toggleSelectedProp(e,t=!1){this.setOptionProp(e,"isSelected",t)}scrollToTop(){const{scrollTop:e}=this.$optionsContainer;e>0&&(this.$optionsContainer.scrollTop=0)}reset(e=!1,t=!1){this.options.forEach(e=>{e.isSelected=!1}),this.beforeValueSet(!0),this.setValue(null,{disableEvent:t,disableValidation:e}),this.afterValueSet(),e&&(s.removeClass(this.$allWrappers,"has-error"),s.toggleAria(this.$allWrappers,"invalid",!1),this.setErrorMessage("")),s.dispatchEvent(this.$ele,"reset")}addOption(e,t){if(!e)return;this.lastOptionIndex+=1;const s=this.getOptionObj({...e,index:this.lastOptionIndex});this.options.push(s),this.sortedOptions.push(s),t&&(this.visibleOptionsCount+=1,this.afterSetOptions())}removeOption(e){(e||0===e)&&(this.options.splice(e,1),this.lastOptionIndex-=1)}removeNewOption(){const e=this.getNewOption();e&&(this.ariaMetadataDirty=!0,this.removeOption(e.index))}sortOptions(e){return e.sort((e,t)=>{const s=e.isSelected||e.isAnySelected,i=t.isSelected||t.isAnySelected;return s||i?s&&(!i||e.index{const s=e.options;e.isAnySelected=s.some(e=>e.isSelected),e.isAnySelected&&t(s)}),t(s),this.destructureOptionGroup(s)}isOptionVisible({data:e,searchValue:s,hasExactOption:i,visibleOptionGroupsMapping:o,searchGroup:n,searchByStartsWith:r}){const a=null!=e.valueNormalized?e.valueNormalized:e.value.toLowerCase();let l=e.labelNormalized;if(null==l){const s=(e.label||"").trim();l=this.searchNormalize&&""!==s?t.normalizeString(s).toLowerCase():s.toLowerCase()}const{description:h,alias:p}=e;let{descriptionNormalized:c}=e;if(null==c){const e=h||"";c=this.searchNormalize&&""!==e.trim()?t.normalizeString(e).toLowerCase():e.toLowerCase()}let u=r?l.startsWith(s):l.includes(s);return!e.isGroupTitle||n&&u||(u=o[e.index]),r||!p||u||(u=p.includes(s)),r||!c||u||(u=c.includes(s)),e.isVisible=u,i||(i=l===s||a===s),{isVisible:u,hasExactOption:i}}structureOptionGroup(e){const t=[],s={};return e.forEach(e=>{if(e.isGroupTitle){const i=[];e.options=i,s[e.index]=i,t.push(e)}}),e.forEach(e=>{e.isGroupOption&&s[e.groupIndex].push(e)}),t}destructureOptionGroup(e){let t=[];return e.forEach(e=>{t.push(e),t=t.concat(e.options)}),t}serverSearch(){s.removeClass(this.$allWrappers,"has-no-search-results"),s.addClass(this.$allWrappers,"server-searching"),this.isInitialized&&!this.isSilentServerSearch&&this.isOpened()&&this.announce(this.loadingText),this.setSelectedOptions(),this.onServerSearch(this.searchValue,this)}removeValue(e){const{selectedValues:i}=this,o=s.getData(e,"value");t.removeItemFromArray(i,o),this.setValueMethod(i)}focus(){this.$wrapper.focus()}enable(){this.$ele.disabled=!1,this.$ele.removeAttribute("disabled"),this.$hiddenInput.removeAttribute("disabled"),s.setAria(this.$wrapper,"disabled",!1),s.changeTabIndex(this.$wrapper,0)}disable(){this.$ele.disabled=!0,this.$ele.setAttribute("disabled",""),this.$hiddenInput.setAttribute("disabled",""),s.setAria(this.$wrapper,"disabled",!0),s.changeTabIndex(this.$wrapper,-1),this.$wrapper.blur()}validate(){if(this.disableValidation)return!0;let e=!1,i="";const{selectedValues:o,minValues:n}=this;return this.required&&(t.isEmpty(o)?(e=!0,i=this.requiredErrorText):this.multiple&&n&&o.length{this.managedTimeouts.delete(s),e()},t);return this.managedTimeouts.add(s),s}clearManagedTimeouts(){this.managedTimeouts&&(this.managedTimeouts.forEach(e=>clearTimeout(e)),this.managedTimeouts.clear())}destroy(){if(this.isDestroyed)return;this.isDestroyed=!0;const{$ele:e}=this;e.virtualSelect=void 0,e.value=void 0,e.innerHTML="",l.openInstances.delete(this),this===l.lastInteractedInstance&&(l.lastInteractedInstance=null),this.serverSearchTimeout&&(clearTimeout(this.serverSearchTimeout),this.serverSearchTimeout=null),this.clearManagedTimeouts(),this.scrollAnimationFrame&&(cancelAnimationFrame(this.scrollAnimationFrame),this.scrollAnimationFrame=null),this.removeEvents(),this.hasDropboxWrapper&&(this.$dropboxWrapper.virtualSelect=void 0,this.$dropboxWrapper.remove()),this.dropboxPopover&&this.dropboxPopover.destroy(),s.removeClass(e,"vscomp-ele"),this.events={},l.unregisterInstance(this)}createSecureTextElements(){this.$secureDiv=document.createElement("div"),this.$secureText=document.createTextNode(""),this.$secureDiv.appendChild(this.$secureText)}secureText(e){return e&&this.enableSecureText?(this.$secureText.nodeValue=e,this.$secureDiv.innerHTML):e}warnIfSecureTextDisabled(){l.secureTextWarningShown||this.enableSecureText||!this.showSecureTextWarning||(l.secureTextWarningShown=!0,console.warn("[virtual-select] Option text (label, value, description) and any `customData` used in markup are rendered as HTML and are NOT escaped because `enableSecureText` is disabled (the default, kept off for performance on large datasets). If any option text can come from untrusted input, set `enableSecureText: true` to prevent XSS. Docs: https://sa-si-dev.github.io/virtual-select/#/properties"))}announce(e){if(!this.$liveRegion)return;const s=t.getPlainText(e||"");this.$liveRegion.textContent!==s&&(this.$liveRegion.textContent=s)}getResultsCountMessage(){const e=this.filteredOptionsCount||0;return 0===e?this.noSearchResultsText:`${e} ${1===e?this.searchResultText:this.searchResultsText}`}getSelectionMessage(){const e=this.selectedValues.length;return 0===e?this.noOptionsSelectedText:this.multiple?`${e} ${1===e?this.optionSelectedText:this.optionsSelectedText}`:`${this.getDisplayValue()||this.selectedValues[0]} ${this.selectedText}`}announceSearchResults(){this.isInitialized&&this.isOpened()&&document.activeElement===this.$searchInput&&this.announce(this.getResultsCountMessage())}toggleRequired(e){this.required=t.convertToBoolean(e),this.$ele.required=this.required,s.toggleAria(this.$allWrappers,"required",this.required),this.required||(s.toggleClass(this.$allWrappers,"has-error",!1),s.toggleAria(this.$allWrappers,"invalid",!1),this.setErrorMessage(""))}toggleOptionSelectedState(e,t){let i=t;void 0===i&&(i=!s.hasClass(e,"selected")),s.toggleClass(e,"selected",i),s.setAria(e,"selected",i)}toggleOptionFocusedState(e,t){e&&(s.toggleClass(e,"focused",t),s.setAttr(e,"tabindex",t?"0":"-1"),t&&document.activeElement!==this.$searchInput&&e.focus(),this.setActiveDescendant(t?e.id:""))}setActiveDescendant(e){s.toggleAria(this.$wrapper,"activedescendant",!!e,e),s.toggleAria(this.$searchInput,"activedescendant",!!e,e)}static setGlobalDefaults(e){if(!e||"object"!=typeof e)return;const t={...e};delete t.ele,delete t.options,l.globalDefaults={...l.globalDefaults,...t}}static resetGlobalDefaults(){l.globalDefaults={}}static getGlobalDefaults(){return{...l.globalDefaults}}static init(e){let t=e.ele;if(!t)return;let s=!1;if("string"==typeof t){t=document.querySelectorAll(t);const e=t.length;if(0===e)return;1===e&&(s=!0)}void 0!==t.length&&void 0!==t.forEach||(t=[t],s=!0);const i=[];return t.forEach(t=>{t.virtualSelect?i.push(t.virtualSelect):(e.ele=t,"SELECT"===t.tagName&&l.setPropsFromSelect(e),i.push(new l(e)))}),s?i[0]:i}static getAttrProps(){const{convertPropToDataAttr:e}=s,t={};return n.forEach(e=>{t[e]=e}),a.forEach(s=>{t[e(s)]=s}),t}static setPropsFromSelect(e){const t=e.ele,i=[],n=[],a=e=>{const t=[];return Array.from(e.children).forEach(e=>{const{value:s}=e,o={value:s};"OPTGROUP"===e.tagName?(o.label=e.getAttribute("label"),o.options=a(e)):o.label=e.innerHTML,t.push(o),e.disabled&&i.push(s),e.selected&&n.push(s)}),t},l=a(t),h=document.createElement("div");s.setAttrFromEle(t,h,Object.keys(r),o),t.parentNode.insertBefore(h,t),t.remove(),e.ele=h,e.options=l,e.disabledOptions=i,e.selectedValue=n}static onFormReset(e){const t=e.target.closest("form");t&&t.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{e.parentElement.virtualSelect.reset(!0)})}static onFormSubmit(e){l.validate(e.target.closest("form"))||e.preventDefault()}static validate(e){if(!e)return!0;let t=!1;return e.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{const s=e.parentElement.virtualSelect.validate();t||s||(t=!0)}),!t}static reset(e=!1,t=!1){this.virtualSelect.reset(e,t)}static setValueMethod(...e){this.virtualSelect.setValueMethod(...e)}static setOptionsMethod(...e){this.virtualSelect.setOptionsMethod(...e)}static setDisabledOptionsMethod(...e){this.virtualSelect.setDisabledOptionsMethod(...e)}static setEnabledOptionsMethod(...e){this.virtualSelect.setEnabledOptionsMethod(...e)}static toggleSelectAll(e){this.virtualSelect.toggleAllOptions(e)}static isAllSelected(){return this.virtualSelect.isAllSelected}static addOptionMethod(e){this.virtualSelect.addOption(e,!0)}static getNewValueMethod(){return this.virtualSelect.getNewValue()}static getDisplayValueMethod(){return this.virtualSelect.getDisplayValue()}static getSelectedOptionsMethod(e){return this.virtualSelect.getSelectedOptions(e)}static getDisabledOptionsMethod(){return this.virtualSelect.getDisabledOptions()}static openMethod(){return this.virtualSelect.openDropbox()}static closeMethod(){return this.virtualSelect.closeDropbox()}static focusMethod(){return this.virtualSelect.focus()}static enableMethod(){return this.virtualSelect.enable()}static disableMethod(){return this.virtualSelect.disable()}static destroyMethod(){return this.virtualSelect.destroy()}static validateMethod(){return this.virtualSelect.validate()}static toggleRequiredMethod(e){return this.virtualSelect.toggleRequired(e)}static onResizeMethod(){document.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{const t=e.parentElement&&e.parentElement.virtualSelect;t&&t.onResize()})}}l.onResizeThrottled=t.throttle(l.onResizeMethod,100),r=l.getAttrProps(),window.VirtualSelect=l,l.openInstances=new Set,l.domObserver=null,l.activeInstances=new Set,l.hasGlobalListeners=!1,l.lastInteractedInstance=null,l.secureTextWarningShown=!1,l.globalDefaults={},"undefined"!=typeof NodeList&&NodeList.prototype&&!NodeList.prototype.forEach&&(NodeList.prototype.forEach=Array.prototype.forEach)}(),function(){"use strict";function e(e){return function(e){if(Array.isArray(e))return t(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,s){if(e){if("string"==typeof e)return t(e,s);var i=Object.prototype.toString.call(e).slice(8,-1);return"Object"===i&&e.constructor&&(i=e.constructor.name),"Map"===i||"Set"===i?Array.from(e):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?t(e,s):void 0}}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function t(e,t){(null==t||t>e.length)&&(t=e.length);for(var s=0,i=new Array(t);ss-o-t.width?"left":"right",vertical:n>i-n-t.height?"top":"bottom"}}},{key:"getAbsoluteCoords",value:function(e){if(e){var t=e.getBoundingClientRect(),s=window.pageXOffset,i=window.pageYOffset;return{width:t.width,height:t.height,top:t.top+i,right:t.right+s,bottom:t.bottom+i,left:t.left+s}}}},{key:"getCoords",value:function(e){return e?e.getBoundingClientRect():{}}},{key:"getData",value:function(e,t,s){if(e){var i=e?e.dataset[t]:"";return"number"===s?i=parseFloat(i)||0:"true"===i?i=!0:"false"===i&&(i=!1),i}}},{key:"setData",value:function(e,t,s){e&&(e.dataset[t]=s)}},{key:"setStyle",value:function(e,t,s){e&&(e.style[t]=s)}},{key:"show",value:function(e){var s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"block";t.setStyle(e,"display",s)}},{key:"hide",value:function(e){t.setStyle(e,"display","none")}},{key:"getHideableParent",value:function(e){for(var t,s=e.parentElement;s;){var i=getComputedStyle(s).overflow;if(-1!==i.indexOf("scroll")||-1!==i.indexOf("auto")){t=s;break}s=s.parentElement}return t}}],s&&function(e,t){for(var s=0;sx?x-b:M:w+p>L&&("right"===T?n="left":w=L+bS?S-u:P:C+c>I&&("bottom"===T?n="top":C=I+up-j&&(G=p-j):"left"!==T&&"right"!==T||((R=g/2+f-H)c-j&&(R=c-j)),s.setStyle(this.$arrowEle,"transform","translate3d(".concat(parseInt(G),"px, ").concat(parseInt(R),"px, 0) ").concat(K))}s.hide(this.$popperEle)}},{key:"resetPosition",value:function(){s.setStyle(this.$popperEle,"transform","none"),this.setPosition()}},{key:"show",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},i=t.resetPosition,o=t.data;clearTimeout(this.exitDelayTimeout),clearTimeout(this.hideDurationTimeout),i&&this.resetPosition(),this.enterDelayTimeout=setTimeout(function(){var t=s.getData(e.$popperEle,"left"),i=s.getData(e.$popperEle,"top"),n="translate3d(".concat(parseInt(t),"px, ").concat(parseInt(i),"px, 0)"),r=e.showDuration;s.show(e.$popperEle,"inline-flex"),s.getCoords(e.$popperEle),s.setStyle(e.$popperEle,"transitionDuration",r+"ms"),s.setStyle(e.$popperEle,"transform",n),s.setStyle(e.$popperEle,"opacity",1),e.showDurationTimeout=setTimeout(function(){"function"==typeof e.afterShowCallback&&e.afterShowCallback(o)},r)},this.enterDelay)}},{key:"hide",value:function(){var e=this,t=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).data;clearTimeout(this.enterDelayTimeout),clearTimeout(this.showDurationTimeout),this.exitDelayTimeout=setTimeout(function(){if(e.$popperEle){var i=parseInt(s.getData(e.$popperEle,"fromLeft")),o=parseInt(s.getData(e.$popperEle,"fromTop")),n="translate3d(".concat(i,"px, ").concat(o,"px, 0)"),r=e.hideDuration;s.setStyle(e.$popperEle,"transitionDuration",r+"ms"),s.setStyle(e.$popperEle,"transform",n),s.setStyle(e.$popperEle,"opacity",0),e.hideDurationTimeout=setTimeout(function(){s.hide(e.$popperEle),"function"==typeof e.afterHideCallback&&e.afterHideCallback(t)},r)}},this.exitDelay)}},{key:"updatePosition",value:function(){s.setStyle(this.$popperEle,"transitionDuration","0ms"),this.resetPosition();var e=parseInt(s.getData(this.$popperEle,"left")),t=parseInt(s.getData(this.$popperEle,"top"));s.show(this.$popperEle,"inline-flex"),s.setStyle(this.$popperEle,"transform","translate3d(".concat(e,"px, ").concat(t,"px, 0)"))}}],t&&function(e,t){for(var s=0;s1&&void 0!==arguments[1]&&arguments[1]}},{key:"removeArrayEmpty",value:function(e){return Array.isArray(e)&&e.length?e.filter(function(e){return!!e}):[]}},{key:"throttle",value:function(e,t){var s,i=0;return function(){for(var o=arguments.length,n=new Array(o),r=0;re.length)&&(t=e.length);for(var s=0,i=new Array(t);s'),e=this.$popover.querySelector(".pop-comp-arrow")),this.$arrowEle=e}}},{key:"destroy",value:function(){this.removeEvents()}}])&&c(t.prototype,s),o&&c(t,o),Object.defineProperty(t,"prototype",{writable:!1}),t;var t,s,o}();d=m.getAttrProps(),window.PopoverComponent=m}(); \ No newline at end of file diff --git a/dist/virtual-select.js b/dist/virtual-select.js index 42bceea..9e289f2 100644 --- a/dist/virtual-select.js +++ b/dist/virtual-select.js @@ -1,5 +1,5 @@ /*! - * Virtual Select v1.3.0 + * Virtual Select v1.4.0 * https://sa-si-dev.github.io/virtual-select * Licensed under MIT (https://github.com/sa-si-dev/virtual-select/blob/master/LICENSE) *//******/ (function() { // webpackBootstrap @@ -191,24 +191,16 @@ class Utils { } /** + * Whether the user has asked the operating system to reduce motion. + * + * Read on each call rather than cached, so a preference changed after page load is picked up + * by the next instance. Guarded for environments without matchMedia. + * * @static - * @param {*} container - * @param {string} text - * @return {boolean} - * @memberof Utils + * @returns {boolean} */ - static willTextOverflow(container, text) { - const tempElement = document.createElement('div'); - tempElement.style.position = 'absolute'; - tempElement.style.visibility = 'hidden'; - tempElement.style.whiteSpace = 'nowrap'; - tempElement.style.fontSize = window.getComputedStyle(container).fontSize; - tempElement.style.fontFamily = window.getComputedStyle(container).fontFamily; - tempElement.textContent = text; - document.body.appendChild(tempElement); - const textWidth = tempElement.clientWidth; - document.body.removeChild(tempElement); - return textWidth > container.clientWidth; + static prefersReducedMotion() { + return typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches; } /** @@ -221,6 +213,83 @@ class Utils { return text.replace(/"/g, '"'); } + /** + * Escape a *raw* string for interpolation into a double-quoted HTML attribute. + * + * Use this only where the input has not already been HTML-escaped - currently the option + * value, which is stored verbatim because it reaches no innerHTML sink. `&` must be escaped + * first, otherwise the `&` introduced by the quote replacement would itself be escaped and + * the attribute would parse back as a literal `"`. + * + * Deliberately NOT used by DomUtils.getAttributesText(), whose inputs are already-escaped + * label text: escaping `&` there would double it and a tooltip would show `&`. That + * asymmetry is the reason this is a separate helper rather than a shared one. + * + * @static + * @param {string} text + * @return {string} + * @memberof Utils + */ + static escapeAttributeValue(text) { + return Utils.getString(text).replace(/&/g, '&').replace(/"/g, '"'); + } + + /** + * Undo the escaping secureText() applies, recovering the text a human should read. + * + * Option label and description are stored HTML-escaped when enableSecureText is on, because + * they are inserted as HTML. Anywhere that text is consumed as *text* instead - an accessible + * name, a live-region announcement - the escape sequences have to come back off, or the user + * is read `&` and `<i class=...`. + * + * `&` is decoded last: doing it first would turn a literal `&lt;` into `<` and then + * into `<`, inventing markup the consumer never wrote. + * + * @static + * @param {string} text + * @return {string} + * @memberof Utils + */ + static decodeSecureText(text) { + return Utils.getString(text).replace(/</g, '<').replace(/>/g, '>').replace(/ /g, '\u00A0').replace(/&/g, '&'); + } + + /** + * Reduce label text to the words a human should hear or read. + * + * Labels may legitimately contain markup - an icon, , a
. Wherever that text is + * consumed as text (an accessible name, a live-region announcement) the markup is meaningless + * and is read out as tag soup. Tags collapse to a single space so adjacent words do not run + * together, so "France
Paris" does not become one word. + * + * The escaping is undone first. With enableSecureText on the label arrives already escaped, so + * the tag pattern found no `<` to match and the markup passed through verbatim - the strip was + * a no-op in exactly the mode escaping is enabled in. + * + * @static + * @param {string} text + * @return {string} + * @memberof Utils + */ + static getPlainText(text) { + return Utils.decodeSecureText(text).replace(/<[^>]+>/gi, ' ').replace(/\s+/g, ' ').trim(); + } + + /** + * Turn a label into text that is safe and sensible inside an aria-label attribute. + * + * Plain text, then escaped for the attribute - covering `&` as well as `"`, so a bare + * ampersand in a label is a valid character reference rather than raw markup, and a double + * quote can no longer close the attribute early and truncate the name. + * + * @static + * @param {string} text + * @returns {string} + */ + static getAriaLabelText(text) { + return Utils.escapeAttributeValue(Utils.getPlainText(text)); + } + /** * @static * @param {string} text @@ -452,6 +521,42 @@ class DomUtils { $ele.setAttribute(name, value); } + /** + * @param {HTMLElement} $ele + * @param {string} name + */ + static removeAttr($ele, name) { + if (!$ele) { + return; + } + $ele.removeAttribute(name); + } + + /** + * Set an aria-* attribute when the state applies, remove it otherwise. + * + * Preferred over writing `aria-x="false"` for states whose absence is meaningful + * (aria-required, aria-invalid): a literal "false" is valid but adds noise that some + * screen readers still verbalise. + * + * @param {HTMLElement | NodeListOf} $ele + * @param {string} name + * @param {boolean} isSet + * @param {string} [value='true'] + */ + static toggleAria($ele, name, isSet, value = 'true') { + if (!$ele) { + return; + } + DomUtils.getElements($ele).forEach($this => { + if (isSet) { + $this.setAttribute(`aria-${name}`, value); + } else { + $this.removeAttribute(`aria-${name}`); + } + }); + } + /** * @param {HTMLElement} $from * @param {HTMLElement} $to @@ -600,7 +705,21 @@ class DomUtils { // @ts-ignore Object.entries(data).forEach(([k, v]) => { if (v !== undefined) { - html += ` ${k}="${v}" `; + /** + * Quotes are escaped here, at the attribute boundary, because this is the only place + * that knows the value is about to be wrapped in double quotes. + * + * The caller that matters is getTooltipAttrText(), which passes option labels through + * to data-tooltip. It used to escape quotes itself but only when containsHTML(label) + * was true, so a payload with no tag in it - `x" data-pwned="1" z="` - went in raw and + * put a live attribute on the value-tag element. Escaping unconditionally here removes + * the condition, and the parser turns " back into a quote, so the attribute still + * reads back as the original string. + * + * String(), not Utils.getString(): the latter maps `false` to '', and some of these + * attributes carry real boolean values (data-tooltip-ellipsis-only, -allow-html). + */ + html += ` ${k}="${Utils.replaceDoubleQuotesWithHTML(String(v))}" `; } }); return html; @@ -672,7 +791,7 @@ const nativeProps = ['autofocus', 'class', 'disabled', 'id', 'multiple', 'name', // the class below has been evaluated (see the assignment at the bottom of this file). // eslint-disable-next-line prefer-const let attrPropsMapping; -const dataProps = ['additionalClasses', 'additionalDropboxClasses', 'additionalDropboxContainerClasses', 'additionalToggleButtonClasses', 'aliasKey', 'allOptionsSelectedText', 'allowNewOption', 'alwaysShowSelectedOptionsCount', 'alwaysShowSelectedOptionsLabel', 'ariaLabelledby', 'ariaLabelText', 'ariaLabelClearButtonText', 'ariaLabelTagClearButtonText', 'ariaLabelSearchClearButtonText', 'autoSelectFirstOption', 'clearButtonText', 'descriptionKey', 'disableAllOptionsSelectedText', 'disableOptionGroupCheckbox', 'disableSelectAll', 'disableValidation', 'dropboxWidth', 'dropboxWrapper', 'emptyValue', 'enableSecureText', 'focusSelectedOptionOnOpen', 'hasOptionDescription', 'hideClearButton', 'hideValueTooltipOnSelectAll', 'keepAlwaysOpen', 'labelKey', 'markSearchResults', 'maxValues', 'maxWidth', 'minValues', 'moreText', 'noOfDisplayValues', 'noOptionsText', 'noSearchResultsText', 'optionHeight', 'optionSelectedText', 'optionsCount', 'optionsSelectedText', 'popupDropboxBreakpoint', 'popupPosition', 'position', 'search', 'searchByStartsWith', 'searchDelay', 'searchFormLabel', 'searchGroup', 'searchNormalize', 'searchPlaceholderText', 'selectAllOnlyVisible', 'selectAllText', 'setValueAsArray', 'showDropboxAsPopup', 'showOptionsOnlyOnSearch', 'showSecureTextWarning', 'showSelectedOptionsFirst', 'showValueAsTags', 'silentInitialValueSet', 'textDirection', 'tooltipAlignment', 'tooltipFontSize', 'tooltipMaxWidth', 'updatePositionThrottle', 'useGroupValue', 'valueKey', 'zIndex']; +const dataProps = ['additionalClasses', 'additionalDropboxClasses', 'additionalDropboxContainerClasses', 'additionalToggleButtonClasses', 'aliasKey', 'allOptionsSelectedText', 'allowNewOption', 'alwaysShowSelectedOptionsCount', 'alwaysShowSelectedOptionsLabel', 'ariaLabelledby', 'ariaLabelText', 'ariaLabelClearButtonText', 'ariaLabelTagClearButtonText', 'ariaLabelSearchClearButtonText', 'autoSelectFirstOption', 'clearButtonText', 'descriptionKey', 'disableAllOptionsSelectedText', 'disableOptionGroupCheckbox', 'disableSelectAll', 'disableValidation', 'dropboxWidth', 'dropboxWrapper', 'emptyValue', 'enableSecureText', 'focusSelectedOptionOnOpen', 'hasOptionDescription', 'hideClearButton', 'hideValueTooltipOnSelectAll', 'keepAlwaysOpen', 'labelKey', 'markSearchResults', 'maxValues', 'maxWidth', 'minValues', 'loadingText', 'minValuesErrorText', 'moreText', 'noOfDisplayValues', 'noOptionsSelectedText', 'noOptionsText', 'noSearchResultsText', 'optionHeight', 'optionSelectedText', 'optionsCount', 'optionsSelectedText', 'popupDropboxBreakpoint', 'popupPosition', 'position', 'requiredErrorText', 'search', 'searchByStartsWith', 'searchDelay', 'searchFormLabel', 'searchGroup', 'searchNormalize', 'searchPlaceholderText', 'searchResultText', 'searchResultsText', 'selectAllOnlyVisible', 'selectAllText', 'selectedText', 'setValueAsArray', 'showDropboxAsPopup', 'showOptionsOnlyOnSearch', 'showSecureTextWarning', 'showSelectedOptionsFirst', 'showValueAsTags', 'silentInitialValueSet', 'textDirection', 'tooltipAlignment', 'tooltipFontSize', 'tooltipMaxWidth', 'updatePositionThrottle', 'useGroupValue', 'valueKey', 'zIndex']; /** Class representing VirtualSelect */ class VirtualSelect { @@ -708,9 +827,20 @@ class VirtualSelect { let toggleButtonClasses = 'vscomp-toggle-button'; const valueTooltip = this.showValueAsTags ? '' : this.getTooltipAttrText(this.placeholder, true, true); const clearButtonTooltip = this.getTooltipAttrText(this.clearButtonText); - const ariaLabelledbyText = this.ariaLabelledby ? `aria-labelledby="${this.ariaLabelledby}"` : ''; - const ariaLabelText = this.ariaLabelText ? `aria-label="${this.ariaLabelText}"` : ''; - const ariaLabelClearBtnTxt = this.ariaLabelClearButtonText ? `aria-label="${this.ariaLabelClearButtonText}"` : ''; + /** + * These props are developer-supplied but still reach an attribute directly, and none of them + * passes through secureText() - so enableSecureText never protected them. A double quote + * closed the attribute early: the payload after it was parsed as markup, and the accessible + * name kept only the prefix, which is a WCAG 4.1.2 defect as much as an injection. + * + * getAriaLabelText() for the accessible names, because it is what AI-14 already applies to + * option and group labels: strip markup, then escape quotes. Plain quote escaping for + * aria-labelledby, which is an IDREF list rather than prose - stripping tags there would hide + * a caller error instead of fixing it. + */ + const ariaLabelledbyText = this.ariaLabelledby ? `aria-labelledby="${Utils.replaceDoubleQuotesWithHTML(Utils.getString(this.ariaLabelledby))}"` : ''; + const ariaLabelText = this.ariaLabelText ? `aria-label="${Utils.getAriaLabelText(this.ariaLabelText)}"` : ''; + const ariaLabelClearBtnTxt = this.ariaLabelClearButtonText ? `aria-label="${Utils.getAriaLabelText(this.ariaLabelClearButtonText)}"` : ''; let isExpanded = false; if (this.additionalClasses) { wrapperClasses += ` ${Utils.sanitizeClassNames(this.additionalClasses)}`; @@ -751,7 +881,7 @@ class VirtualSelect { const html = `
- +
${this.placeholder} @@ -766,7 +896,12 @@ class VirtualSelect { ${this.renderDropbox({ wrapperClasses })} -
`; +
+ +
+ +
`; this.$ele.innerHTML = html; this.$body = document.querySelector('body'); this.$wrapper = this.$ele.querySelector('.vscomp-wrapper'); @@ -782,6 +917,33 @@ class VirtualSelect { this.$clearButton = this.$ele.querySelector('.vscomp-clear-button'); this.$valueText = this.$ele.querySelector('.vscomp-value'); this.$hiddenInput = this.$ele.querySelector('.vscomp-hidden-input'); + + /** + * The submitting field's name is set as a DOM property, not interpolated into the template. + * + * `name="${this.name}"` made the attribute an HTML sink: a double quote closed it early, so + * the remainder of the value was parsed as markup (real elements, an injection) while the + * field kept only the truncated prefix - or, when the payload also swallowed the following + * `class="vscomp-hidden-input"`, no field was found at all and the first setValue() threw + * inside the constructor. Either way the form silently stopped submitting the right name, + * and that included legitimate names such as `items["a"]`. + * + * A property assignment performs no HTML parsing, so there is nothing to break out of and + * nothing to escape - which is also why `name` no longer goes through secureText(): the + * escaping only ever protected this sink, and applying it here corrupted the submitted + * field name into `items["a"]`. + */ + this.$hiddenInput.name = this.name; + + /** + * Both live outside the wrapper, as siblings, because the wrapper is the combobox: for an + * instance mounted without ariaLabelText/ariaLabelledby the combobox takes its accessible + * name from its contents, and visually-hidden text still joins that computation - so a + * status update or validation message inside it would be read as part of the field's *name*. + * A sibling can be announced (live region) or associated (aria-describedby) without that. + */ + this.$liveRegion = this.$ele.querySelector('.vscomp-live-region'); + this.$errorMessage = this.$ele.querySelector('.vscomp-error-message'); this.$dropbox = this.$dropboxContainer.querySelector('.vscomp-dropbox'); this.$dropboxCloseButton = this.$dropboxContainer.querySelector('.vscomp-dropbox-close-button'); this.$dropboxContainerBottom = this.$dropboxContainer.querySelector('.vscomp-dropbox-container-bottom'); @@ -811,7 +973,9 @@ class VirtualSelect {
-
+
@@ -844,8 +1008,16 @@ class VirtualSelect { return html; } renderOptions() { - // Calculate ARIA metadata before rendering to ensure it's always up to date - this.calculateAriaMetadata(); + /** + * The ARIA scan walks every option, so running it per render made scrolling O(n) per + * event (~3.9 ms/call at 100k). aria-setsize/aria-posinset only change when the + * filtered set or its order changes, never when the virtualisation window moves, so + * recompute on a dirty flag instead. Everything that alters the set marks it dirty. + */ + if (this.ariaMetadataDirty) { + this.calculateAriaMetadata(); + this.ariaMetadataDirty = false; + } let html = ''; const visibleOptions = this.getVisibleOptions(); let checkboxHtml = ''; @@ -908,14 +1080,14 @@ class VirtualSelect { ariaDisabledText = 'aria-disabled="true"'; } if (d.isGroupTitle) { - groupName = d.label; + /** carried into every child's aria-label below, so strip markup once here */ + groupName = Utils.getAriaLabelText(d.label); optionClasses += ' group-title'; if (disableOptionGroupCheckbox) { leftSection = ''; } else if (this.multiple) { - const groupLabel = Utils.replaceDoubleQuotesWithHTML(Utils.getString(d.label)); - const selectAllText = Utils.replaceDoubleQuotesWithHTML(Utils.getString(this.selectAllText)); - ariaLabel = `aria-label="${groupLabel}, ${selectAllText}"`; + const selectAllText = Utils.getAriaLabelText(this.selectAllText); + ariaLabel = `aria-label="${groupName}, ${selectAllText}"`; } } if (isSelected) { @@ -932,13 +1104,13 @@ class VirtualSelect { * is on - an XSS bypass. secureText is a no-op when enableSecureText is disabled, * keeping the existing behaviour for consumers that intentionally pass raw text. */ - const groupNameText = this.secureText(Utils.getString(d.customData.group_name)); - const groupDescText = this.secureText(Utils.getString(d.customData.description)); + const groupNameText = Utils.getAriaLabelText(this.secureText(Utils.getString(d.customData.group_name))); + const groupDescText = Utils.getAriaLabelText(this.secureText(Utils.getString(d.customData.description))); groupName = d.customData.group_name !== undefined ? `${groupNameText}, ` : ''; const optionDesc = d.customData.description !== undefined ? ` ${groupDescText},` : ''; - ariaLabel = `aria-label="${groupName} ${d.label}, ${optionDesc}"`; + ariaLabel = `aria-label="${groupName} ${Utils.getAriaLabelText(d.label)}, ${optionDesc}"`; } else { - ariaLabel = `aria-label="${groupName}, ${d.label}"`; + ariaLabel = `aria-label="${groupName}, ${Utils.getAriaLabelText(d.label)}"`; } } if (hasLabelRenderer) { @@ -964,8 +1136,23 @@ class VirtualSelect { ariaAttrs += ` aria-posinset="${d.filteredIndex}"`; } } + + /** + * The option value is an untrusted string going straight into an attribute, so a double + * quote in it closed data-value early and everything after it was parsed as markup - a + * value of `x" data-pwned="1" z="` put a live data-pwned attribute on the option row, + * whether or not enableSecureText was on. + * + * `&` is escaped here as well as `"`, because the value is now stored verbatim (it reaches + * no innerHTML sink, so escaping it only made the option unaddressable - see secureText). + * Both together keep the attribute round-tripping: the parser turns `&` and `"` + * back into `&` and `"`, and setOptionAttr() rewrites data-value through the DOM API on + * every render anyway. + */ + const optionValueAttr = Utils.escapeAttributeValue(d.value); html += `
${leftSection} @@ -988,20 +1175,40 @@ class VirtualSelect { let checkboxHtml = ''; let searchInput = ''; if (this.multiple && !this.disableSelectAll) { - checkboxHtml = ` + /** + * role="checkbox" + aria-checked so the control is announced as a checkbox and its + * state changes are audible. Without them it exposed as a generic element and every + * select/deselect was silent to assistive technology (WCAG 4.1.2 / 1.3.1). + * aria-checked is kept in sync by toggleAllOptionsClass(). + */ + /** + * selectAllText has two sinks, and only the attribute one is escaped. + * + * The visible label below is rendered as HTML and that works today - `Pick all` + * produces a real - so escaping it would be a visible regression for anyone styling + * the Select All label. The accessible name, by contrast, was raw: a quote broke out of + * the attribute, and markup was announced as tag soup. getAriaLabelText() is the same + * treatment the group-header aria-label a few methods up already applies to this exact + * prop, which is why that sink was safe while this one was not. + */ + checkboxHtml = ` ${this.selectAllText} `; } if (this.hasSearch) { - const ariaLabelSearchClearBtnTxt = this.ariaLabelSearchClearButtonText ? `aria-label="${this.ariaLabelSearchClearButtonText}"` : ''; + const ariaLabelSearchClearBtnTxt = this.ariaLabelSearchClearButtonText ? `aria-label="${Utils.getAriaLabelText(this.ariaLabelSearchClearButtonText)}"` : ''; searchInput = ` - + ×`; } const html = `
@@ -1132,14 +1339,29 @@ class VirtualSelect { e.preventDefault(); this.focusFirstVisibleOption(); } - if (document.activeElement === this.$toggleAllButton && key === 13) { + + /** + * Space is the expected activation key for role="checkbox"; Enter is kept for + * backwards compatibility. preventDefault stops Space from scrolling the page + * (the previous behaviour, since the key was unhandled here). + */ + if (document.activeElement === this.$toggleAllButton && (key === 13 || key === 32)) { + e.preventDefault(); this.toggleAllOptions(); return; } - // Handle the Escape key when showing the dropdown as a popup, closing it + /** + * Escape must close the dropdown in every layout (WCAG 2.1.1 / 2.1.2). + * The element that contains the focused node differs by layout: with an external + * `dropboxWrapper` the dropbox is portalled out of $wrapper, so containment has to be + * tested against $dropboxWrapper. In every other case - including the default + * `dropboxWrapper: 'self'` on desktop - the dropbox lives inside $wrapper. Selecting + * $dropboxWrapper unconditionally for non-popup layouts left it `undefined` under the + * default config, so the branch never ran and Escape did nothing. + */ if (key === 27 || e.key === 'Escape') { - const wrapper = this.showAsPopup ? this.$wrapper : this.$dropboxWrapper; + const wrapper = this.hasDropboxWrapper && !this.showAsPopup ? this.$dropboxWrapper : this.$wrapper; if (wrapper && (document.activeElement === wrapper || wrapper.contains(document.activeElement)) && !this.keepAlwaysOpen) { this.closeDropbox(); return; @@ -1157,33 +1379,34 @@ class VirtualSelect { this.openDropbox(); } } - onDownArrowPress(e) { - // Allow default behavior (cursor movement) when search input is focused - if (document.activeElement === this.$searchInput) { - return; - } + + /** + * Move the highlight without moving DOM focus. + * + * Previously both arrow handlers bailed out whenever the search input had focus, to let + * the caret move. But opening the dropdown focuses the search input, so in the default + * flow the arrows did nothing at all and no option was ever highlighted (WCAG 2.1.1). + * The APG editable-combobox pattern is what applies here: Up/Down drive the list while + * focus stays in the field, and the active option is published as aria-activedescendant. + * + * @param {KeyboardEvent} e + * @param {'next' | 'previous'} direction + */ + navigateOptions(e, direction) { e.preventDefault(); if (this.isOpened()) { this.focusOption({ - direction: 'next' + direction }); } else { this.openDropbox(); } } + onDownArrowPress(e) { + this.navigateOptions(e, 'next'); + } onUpArrowPress(e) { - // Allow default behavior (cursor movement) when search input is focused - if (document.activeElement === this.$searchInput) { - return; - } - e.preventDefault(); - if (this.isOpened()) { - this.focusOption({ - direction: 'previous' - }); - } else { - this.openDropbox(); - } + this.navigateOptions(e, 'previous'); } onBackspaceOrDeletePress(e) { if (e.target === this.$wrapper) { @@ -1220,8 +1443,24 @@ class VirtualSelect { this.reset(); } } + + /** + * Scroll fires many times per drag and each event triggered a full re-render + * (~9.5 ms at 100k unthrottled, ~44 ms at 4x CPU), so the main thread stayed blocked for + * the whole gesture. Coalesce into at most one re-render per animation frame; the pending + * frame is cancelled in destroy() so it cannot run against a torn-down instance. + */ onOptionsScroll() { - this.setVisibleOptions(true); + if (this.scrollAnimationFrame) { + return; + } + this.scrollAnimationFrame = requestAnimationFrame(() => { + this.scrollAnimationFrame = null; + if (this.isDestroyed) { + return; + } + this.setVisibleOptions(true); + }); } onOptionsClick(e) { const $option = e.target.closest('.vscomp-option'); @@ -1453,6 +1692,12 @@ class VirtualSelect { if (this.autofocus) { this.focus(); } + + /** + * Marks the end of construction. Live-region announcements are suppressed until + * here so an initial value or the first render does not speak on page load. + */ + this.isInitialized = true; } catch (e) { this.destroy(); throw e; @@ -1502,6 +1747,15 @@ class VirtualSelect { afterSetSearchValue() { if (this.hasServerSearch) { clearTimeout(this.serverSearchTimeout); + + /** + * A search the user types is never silent, whatever state a previous close left behind. + * The other half of the lifecycle lives in closeDropbox()/openDropbox(): closing marks + * the instance silent *after* its own setSearchValue('') runs, so it does not matter + * what this assignment does during the close - but it must not matter, which is why + * this is unconditional rather than `= this.isClosing`. + */ + this.isSilentServerSearch = false; this.serverSearchTimeout = setTimeout(() => { this.serverSearch(); }, this.searchDelay); @@ -1511,9 +1765,16 @@ class VirtualSelect { if (this.selectAllOnlyVisible) { this.toggleAllOptionsClass(); } - this.focusOption({ - focusFirst: true - }); + + /** a closing dropbox must not take a highlight back - see closeDropbox() */ + if (!this.isClosing) { + this.focusOption({ + focusFirst: true + }); + } + if (!this.hasServerSearch) { + this.announceSearchResults(); + } } afterSetVisibleOptionsCount() { this.scrollToTop(); @@ -1536,7 +1797,19 @@ class VirtualSelect { this.setSearchValue('', false, true); } if (!keepValue) { - this.reset(); + /** + * reset() validates, and validation announces - so replacing the options used to speak a + * validation failure for an interaction the user never made. Scoped to this one call rather + * than the whole method, and released in a finally: a stuck flag would silently suppress + * every later error announcement, which is far harder to diagnose than an exception (the + * lesson from the isClosing guard in closeDropbox()). + */ + this.isRefreshingOptions = true; + try { + this.reset(); + } finally { + this.isRefreshingOptions = false; + } } } /** after event methods - end */ @@ -1599,6 +1872,14 @@ class VirtualSelect { this.optionsSelectedText = options.optionsSelectedText; this.optionSelectedText = options.optionSelectedText; this.allOptionsSelectedText = options.allOptionsSelectedText; + /** live-region announcement texts (see announce/getResultsCountMessage) */ + this.searchResultsText = options.searchResultsText; + this.searchResultText = options.searchResultText; + this.noOptionsSelectedText = options.noOptionsSelectedText; + this.selectedText = options.selectedText; + this.loadingText = options.loadingText; + this.requiredErrorText = options.requiredErrorText; + this.minValuesErrorText = options.minValuesErrorText; this.clearButtonText = options.clearButtonText; this.moreText = options.moreText; this.placeholder = options.placeholder; @@ -1613,7 +1894,8 @@ class VirtualSelect { this.zIndex = parseInt(options.zIndex, 10); this.maxValues = parseInt(options.maxValues, 10); this.minValues = parseInt(options.minValues, 10); - this.name = this.secureText(options.name); + /** not escaped: the only sink is the hidden input's `name` *property* (see renderWrapper) */ + this.name = options.name; this.additionalClasses = options.additionalClasses; this.additionalDropboxClasses = options.additionalDropboxClasses; this.additionalDropboxContainerClasses = options.additionalDropboxContainerClasses; @@ -1635,6 +1917,16 @@ class VirtualSelect { this.showDuration = parseInt(options.showDuration, 10); this.hideDuration = parseInt(options.hideDuration, 10); + /** + * The open/close animation is driven from JS as well as CSS, so the stylesheet's + * prefers-reduced-motion rule alone would still leave the popover animating for + * showDuration/hideDuration milliseconds. Honour the preference here too. + */ + if (Utils.prefersReducedMotion()) { + this.showDuration = 0; + this.hideDuration = 0; + } + /** @type {string[]} */ this.selectedValues = []; /** @type {virtualSelectOption[]} */ @@ -1663,13 +1955,27 @@ class VirtualSelect { this.optionsHeight = this.getOptionsHeight(); this.uniqueId = this.getUniqueId(); this.shouldFocusWrapperOnClose = true; // Initialize focus management property + this.isClosing = false; + /** true from closeDropbox() until the next openDropbox() - see closeDropbox() */ + this.isSilentServerSearch = false; this.ariaSetSize = 0; + this.ariaMetadataDirty = true; } /** * @param {virtualSelectOptions} options */ setDefaultProps(options) { + const globalDefaults = VirtualSelect.globalDefaults; + + /** + * Resolve a prop across the precedence chain for the few defaults that are derived + * from another prop, so a page-level default still drives them. + * @param {string} key + */ + const resolve = key => options[key] !== undefined ? options[key] : globalDefaults[key]; + const keepAlwaysOpen = resolve('keepAlwaysOpen'); + const hasOptionDescription = resolve('hasOptionDescription'); const defaultOptions = { dropboxWrapper: 'self', valueKey: 'value', @@ -1693,10 +1999,19 @@ class VirtualSelect { moreText: 'more...', optionsSelectedText: 'options selected', optionSelectedText: 'option selected', + /** live-region announcements (WCAG 4.1.3) - overridable for localisation */ + searchResultsText: 'results available', + searchResultText: 'result available', + noOptionsSelectedText: 'No options selected', + selectedText: 'selected', + loadingText: 'Loading results', + /** validation messages; {count} in minValuesErrorText is replaced with minValues */ + requiredErrorText: 'This field is required', + minValuesErrorText: 'Select at least {count} options', allOptionsSelectedText: 'All', placeholder: 'Select', position: 'bottom left', - zIndex: options.keepAlwaysOpen ? 1 : 2, + zIndex: keepAlwaysOpen ? 1 : 2, tooltipFontSize: '14px', tooltipAlignment: 'center', tooltipMaxWidth: '300px', @@ -1718,11 +2033,38 @@ class VirtualSelect { showDuration: 300, hideDuration: 200 }; - if (options.hasOptionDescription) { + if (hasOptionDescription) { defaultOptions.optionsCount = 4; defaultOptions.optionHeight = '50px'; } - return Object.assign(defaultOptions, options); + + /** + * Precedence: per-instance options > page-level globals > built-in defaults. + * Globals let a host turn a policy on once (notably enableSecureText) instead of + * repeating it at every call site, while an instance can still opt out explicitly. + */ + /** + * `undefined` means "not supplied", so those keys are dropped before merging. + * + * Object.assign copies own enumerable keys *including* ones whose value is undefined, so a prop + * forwarded from an unset variable - `enableSecureText: wrapper.sanitizeValues`, the shape a + * host wrapper naturally produces - overwrote the page-level global instead of falling back to + * it. A host could call setGlobalDefaults({ enableSecureText: true }) and still get escaping + * off at every such call site, with nothing to show it had been overridden. + * + * This also makes the merge agree with the resolve() helper above, which already treats + * undefined as absent; the two disagreed inside the same method. + */ + const supplied = source => { + const result = {}; + Object.keys(source || {}).forEach(key => { + if (source[key] !== undefined) { + result[key] = source[key]; + } + }); + return result; + }; + return Object.assign(defaultOptions, supplied(globalDefaults), supplied(options)); } setPropsFromElementAttr(options) { const $ele = options.ele; @@ -1746,6 +2088,8 @@ class VirtualSelect { $ele.name = this.name; $ele.disabled = false; $ele.required = this.required; + /** expose the constraint itself, not just the failure (WCAG 3.3.1) */ + DomUtils.toggleAria(this.$allWrappers, 'required', this.required); $ele.autofocus = this.autofocus; $ele.multiple = this.multiple; $ele.form = $ele.closest('form'); @@ -1774,8 +2118,23 @@ class VirtualSelect { } } setValueMethod(newValue, silentChange) { - const valuesMapping = {}; - const valuesOrder = {}; + /** + * Option values are untrusted strings used as keys, so every value-keyed lookup in this + * file is built with Object.create(null) rather than `{}`. + * + * This is not about prototype pollution - `mapping['__proto__'] = true` on a plain object + * calls the inherited setter, which ignores a non-object value, so nothing is written and + * Object.prototype stays intact. The damage is to reads: `mapping['__proto__']` returns + * the inherited Object.prototype, which is truthy but never `=== true`, and these lookups + * all compare against `true`. An option whose value is `__proto__` was therefore + * selectable by click (that path reads data-value, not a mapping) but invisible to + * setValue / setDisabledOptions / setEnabledOptions, so a selection the app could read + * back could not be restored - and under allowNewOption it was mistaken for an unknown + * value and duplicated. A null prototype has no inherited members, so an arbitrary string + * key behaves like any other. + */ + const valuesMapping = Object.create(null); + const valuesOrder = Object.create(null); let validValues = []; const isMultiSelect = this.multiple; // Normalize input value first @@ -1838,7 +2197,7 @@ class VirtualSelect { setGroupOptionsValue(preparedValues) { const selectedValues = []; const selectedGroups = {}; - const valuesMapping = {}; + const valuesMapping = Object.create(null); preparedValues.forEach(d => { valuesMapping[d] = true; }); @@ -1899,7 +2258,7 @@ class VirtualSelect { } } else { disabledOptionsArr = disabledOptions.map(d => d.toString()); - const disabledOptionsMapping = {}; + const disabledOptionsMapping = Object.create(null); disabledOptionsArr.forEach(d => { disabledOptionsMapping[d] = true; }); @@ -1933,7 +2292,7 @@ class VirtualSelect { return d; }); } else { - const enabledOptionsMapping = {}; + const enabledOptionsMapping = Object.create(null); enabledOptions.forEach(d => { enabledOptionsMapping[d] = true; }); @@ -1968,7 +2327,7 @@ class VirtualSelect { const getAlias = this.getAlias.bind(this); let index = 0; let hasOptionGroup = false; - const disabledOptionsMapping = {}; + const disabledOptionsMapping = Object.create(null); let hasEmptyValueOption = false; this.disabledOptions.forEach(d => { disabledOptionsMapping[d] = true; @@ -1981,8 +2340,25 @@ class VirtualSelect { [labelKey]: d }; } - const value = secureText(getString(d[valueKey])); - const label = secureText(getString(d[labelKey])); + + /** + * `value` is stored verbatim; only `label` and `description` are escaped. + * + * Escaping is for HTML sinks, and the value has none: it goes into the `data-value` + * attribute (escaped there, at the boundary) and is otherwise only compared or used as a + * map key. Escaping it stored an identity the caller could not name - `a&b` became + * `a&b`, so setValue(['a&b']) matched nothing and a value read back could not be set + * again. + * + * The normalised search keys derive from the *raw* text for the same reason: they are + * matched against what the user types into the search box, which is never HTML-escaped. + * Deriving them from the escaped text meant no query could match text containing `&`, + * `<` or `>`. + */ + const rawValue = getString(d[valueKey]); + const rawLabel = getString(d[labelKey]); + const value = rawValue; + const label = secureText(rawLabel); const childOptions = d.options; const isGroupTitle = !!childOptions; const option = { @@ -1990,7 +2366,7 @@ class VirtualSelect { value, valueNormalized: value.toLowerCase(), label, - labelNormalized: this.searchNormalize && label.trim() !== '' ? Utils.normalizeString(label).toLowerCase() : label.toLowerCase(), + labelNormalized: this.searchNormalize && rawLabel.trim() !== '' ? Utils.normalizeString(rawLabel).toLowerCase() : rawLabel.toLowerCase(), alias: getAlias(d[aliasKey]), isVisible: convertToBoolean(d.isVisible, true), isNew: d.isNew || false, @@ -2008,9 +2384,10 @@ class VirtualSelect { option.groupIndex = d.groupIndex; } if (hasOptionDescription) { - const description = secureText(getString(d[descriptionKey])); - option.description = description; - option.descriptionNormalized = this.searchNormalize && description.trim() !== '' ? Utils.normalizeString(description).toLowerCase() : description.toLowerCase(); + const rawDescription = getString(d[descriptionKey]); + option.description = secureText(rawDescription); + /** normalised from the raw text, so a query containing `&` can match - see above */ + option.descriptionNormalized = this.searchNormalize && rawDescription.trim() !== '' ? Utils.normalizeString(rawDescription).toLowerCase() : rawDescription.toLowerCase(); } if (d.customData) { option.customData = d.customData; @@ -2056,7 +2433,7 @@ class VirtualSelect { /** merging already selected options details with new options */ if (selectedOptions.length) { - const newOptionsValueMapping = {}; + const newOptionsValueMapping = Object.create(null); optionsUpdated = true; newOptions.forEach(d => { newOptionsValueMapping[d.value] = true; @@ -2090,11 +2467,32 @@ class VirtualSelect { } this.setVisibleOptionsCount(); DomUtils.removeClass(this.$allWrappers, 'server-searching'); + + /** + * Replace the "loading" message with the outcome of the fetch - for an open dropdown. + * + * isOpened() alone is not enough: the `closed` class arrives with the hide transition, + * so a response landing just after Escape still saw an "open" dropdown. The silent flag + * (see closeDropbox) covers that window and the whole closed period; opening lifts it. + * + * The count always describes the list as rendered *now*, not the fetch that triggered it. + * setServerOptions() carries no request identity, so responses cannot be matched to + * searches - when a stale response overwrites the list of an open dropdown, what is + * announced is exactly what the user sees, and the newer response re-announces when it + * lands. The local path announces the currently visible matches on the same principle + * (announceSearchResults additionally requires focus in the search input, which a + * response arriving whenever the host answers cannot demand). + */ + if (this.isInitialized && !this.isSilentServerSearch && this.isOpened()) { + this.announce(this.getResultsCountMessage()); + } } setSelectedOptions() { this.selectedOptions = this.options.filter(d => d.isSelected); } setSortedOptions() { + /** order drives aria-posinset */ + this.ariaMetadataDirty = true; let sortedOptions = [...this.options]; if (this.showSelectedOptionsFirst && this.selectedValues.length) { if (this.hasOptionGroup) { @@ -2178,8 +2576,26 @@ class VirtualSelect { DomUtils.toggleClass(this.$allWrappers, 'max-value-selected', this.isMaxValuesSelected); DomUtils.setAttr(this.$clearButton, 'tabindex', hasValue ? '0' : '-1'); DomUtils.setAria(this.$clearButton, 'hidden', hasValue === false); + let isValid = true; if (!disableValidation) { - this.validate(); + isValid = this.validate(); + } + + /** + * Selection changes are otherwise conveyed only by the (visual) value text. + * Guarded on isInitialized so a value supplied at construction time is not + * announced before the user has interacted with anything. + * + * Skipped when validation just failed. validate() announces its message through the same + * polite region, and a polite region is read from its *final* content - so announcing the + * selection summary here overwrote the validation message in the same tick and the user + * never heard it. That silenced every interactive path (the clear button, deselecting below + * minValues) while still setting aria-invalid and showing the message on screen, which is + * the 3.3.1 failure this region exists to fix. The error is the more urgent of the two, and + * it already implies the selection state. + */ + if (this.isInitialized && isValid) { + this.announce(this.getSelectionMessage()); } if (!disableEvent) { DomUtils.dispatchEvent(this.$ele, 'change', true); @@ -2224,17 +2640,37 @@ class VirtualSelect { valueText.push(label); selectedValuesCount += 1; if (showValueAsTags) { - // Will cause text overflow in runtime and if so,the tooltip information is prepared - const valueTooltipForTags = Utils.willTextOverflow($valueText.parentElement, label) ? this.getTooltipAttrText(label, false, true) : ''; + /** + * The tooltip is attached to the tag's *content* span, with ellipsisOnly, so the + * tooltip plugin runs `scrollWidth > offsetWidth` on the real box at hover time. + * + * This used to be decided here, before the tag existed, by measuring the label + * off-screen against `.vscomp-toggle-button` - an element ~73px wider than the space + * the tag text actually gets, at that element's 14px rather than the tag's 12px. Both + * errors are gone by construction once the rendered box is the measurement (#487). + * + * The content span rather than `.vscomp-value-tag`: the tag is `inline-flex` and its + * content span carries `width: calc(100% - 24px)`, so the span clips while the tag + * never reports an overflow of its own - measured, a clipped tag reads + * scrollWidth 260 / offsetWidth 262. + * + * Deferring to hover also means no layout work at render, and a correct answer after + * a resize or when the control is first rendered inside a hidden container - none of + * which a render-time measurement can give. It matches how the non-tag value text has + * always worked (see getToggleButtonHtml). + */ + const valueTagTooltip = this.getTooltipAttrText(label, true, true); - // replace is nedded to remove html tags from aria-label (ex: when there is an icon in the label) + /** markup in the label would otherwise land in the accessible name; a double + * quote in it would break out of the attribute entirely */ let ariaLabelClearBtnTxt = ''; if (this.ariaLabelTagClearButtonText) { - const stripHtmlLabel = label.replace(/<[^>]+>/ig, '').trim(); - ariaLabelClearBtnTxt = `aria-label="${stripHtmlLabel}, ${this.ariaLabelTagClearButtonText}"`; + const stripHtmlLabel = Utils.getAriaLabelText(label); + const clearButtonText = Utils.getAriaLabelText(this.ariaLabelTagClearButtonText); + ariaLabelClearBtnTxt = `aria-label="${stripHtmlLabel}, ${clearButtonText}"`; } - const valueTagHtml = ` - ${label} + const valueTagHtml = ` + ${label} { valuesMapping[d] = true; }); @@ -2501,7 +2950,7 @@ class VirtualSelect { return; } const setNewOption = this.setNewOption.bind(this); - const availableValuesMapping = {}; + const availableValuesMapping = Object.create(null); this.options.forEach(d => { availableValuesMapping[d.value] = true; }); @@ -2596,7 +3045,7 @@ class VirtualSelect { if (this.showSelectedOptionsFirst || !this.focusSelectedOptionOnOpen || selectedValues.length === 0) { return; } - const valuesMapping = {}; + const valuesMapping = Object.create(null); let selectedOptionIndex; selectedValues.forEach(d => { valuesMapping[d] = true; @@ -2671,9 +3120,11 @@ class VirtualSelect { return startIndex; } getTooltipAttrText(text, ellipsisOnly = false, allowHtml = false) { - const tootltipText = Utils.containsHTML(text) ? Utils.replaceDoubleQuotesWithHTML(text) : text; + /** quotes are escaped unconditionally by getAttributesText(); escaping again here would + * leave a literal " in the tooltip, and the old containsHTML() condition is what + * let a tag-free payload through in the first place */ const data = { - 'data-tooltip': tootltipText || '', + 'data-tooltip': text || '', 'data-tooltip-enter-delay': this.tooltipEnterDelay, 'data-tooltip-z-index': this.zIndex, 'data-tooltip-font-size': this.tooltipFontSize, @@ -2697,17 +3148,18 @@ class VirtualSelect { getString } = Utils; const secureText = this.secureText.bind(this); - const value = secureText(getString(data.value)); - const label = secureText(getString(data.label)); - const description = secureText(getString(data.description)); + /** value stored verbatim, search keys derived from the raw text - see setOptions() */ + const rawValue = getString(data.value); + const rawLabel = getString(data.label); + const rawDescription = getString(data.description); return { index: data.index, - value, - valueNormalized: value.toLowerCase(), - label, - labelNormalized: this.searchNormalize && label.trim() !== '' ? Utils.normalizeString(label).toLowerCase() : label.toLowerCase(), - description, - descriptionNormalized: this.searchNormalize && description.trim() !== '' ? Utils.normalizeString(description).toLowerCase() : description.toLowerCase(), + value: rawValue, + valueNormalized: rawValue.toLowerCase(), + label: secureText(rawLabel), + labelNormalized: this.searchNormalize && rawLabel.trim() !== '' ? Utils.normalizeString(rawLabel).toLowerCase() : rawLabel.toLowerCase(), + description: secureText(rawDescription), + descriptionNormalized: this.searchNormalize && rawDescription.trim() !== '' ? Utils.normalizeString(rawDescription).toLowerCase() : rawDescription.toLowerCase(), alias: this.getAlias(data.alias), isCurrentNew: data.isCurrentNew || false, isNew: data.isNew || false, @@ -2733,7 +3185,7 @@ class VirtualSelect { return index; } getNewValue() { - const valuesMapping = {}; + const valuesMapping = Object.create(null); this.newValues.forEach(d => { valuesMapping[d] = true; }); @@ -2791,7 +3243,7 @@ class VirtualSelect { } }); if (keepSelectionOrder) { - const valuesOrder = {}; + const valuesOrder = Object.create(null); selectedValues.forEach((d, i) => { valuesOrder[d] = i; }); @@ -2805,7 +3257,7 @@ class VirtualSelect { labelKey, disabledOptions } = this; - const disabledOptionsValueMapping = {}; + const disabledOptionsValueMapping = Object.create(null); const result = []; disabledOptions.forEach(value => { disabledOptionsValueMapping[value] = true; @@ -2932,6 +3384,15 @@ class VirtualSelect { // Add to open instances VirtualSelect.openInstances.add(this); + + /** + * The silence a close imposed (see closeDropbox) must not outlive the closed state: + * from now on the list is visible, so a fetch that fires or resolves against this open + * dropdown describes what the user is looking at and has to be announced - including a + * host push refreshing the options, and the close-time reset when it lands only after + * the user has already reopened. + */ + this.isSilentServerSearch = false; DomUtils.setAttr(this.$dropboxWrapper, 'tabindex', '0'); DomUtils.setAria(this.$dropboxWrapper, 'hidden', false); DomUtils.setAttr(this.$dropboxContainerTop, 'tabindex', '0'); @@ -2942,6 +3403,13 @@ class VirtualSelect { DomUtils.setStyle(this.$dropboxContainer, 'display', 'inline-flex'); } else { DomUtils.dispatchEvent(this.$ele, 'beforeOpen'); + /** + * The wrapper is the one combobox and the one carrier of aria-expanded. The search + * input deliberately is not a second combobox: nesting one combobox inside another is + * a structure screen readers disagree on, and aria-expanded is not a supported state + * of the input's implicit textbox role - which does support the wiring the input + * needs (aria-autocomplete, aria-controls, aria-activedescendant). + */ DomUtils.setAria(this.$wrapper, 'expanded', true); } this.setDropboxWrapperWidth(); @@ -3002,9 +3470,21 @@ class VirtualSelect { } else { DomUtils.dispatchEvent(this.$ele, 'beforeClose'); DomUtils.setAria(this.$wrapper, 'expanded', false); - DomUtils.setAria(this.$wrapper, 'activedescendant', ''); - // Also clear aria-activedescendant on the listbox container - DomUtils.setAria(this.$dropboxContainer, 'activedescendant', ''); + /** + * No option is active once the list is gone - and the highlight has to go with it, + * here, synchronously. + * + * afterHidePopper() already calls removeOptionFocus(), but for popover-backed + * instances it only runs when the hide transition ends (~200ms later). Until then the + * previous highlight and `focusedOptionIndex` survived the close, so reopening within + * that window resumed navigation from the old position instead of the first option: + * the next Up/Down moved one step past where the user expected, which on a grouped + * multi-select meant Enter landed on the first child option instead of toggling the + * group title. removeOptionFocus() is a no-op when nothing is highlighted, so leaving + * the afterHidePopper() call in place costs nothing and still covers the silent path. + */ + this.removeOptionFocus(); + this.setActiveDescendant(''); } if (this.dropboxPopover && !isSilent) { this.dropboxPopover.hide(); @@ -3017,7 +3497,48 @@ class VirtualSelect { } else { this.afterHidePopper(); } - this.setSearchValue(''); + + /** + * Clearing the filter runs afterSetSearchValue(), which highlights the first visible + * option again. That undid the removeOptionFocus() above whenever the user had typed + * something: the highlight and aria-activedescendant came straight back on a combobox + * already marked aria-expanded="false", and focusOption() pulled DOM focus onto an option + * that is about to be display:none - so the keyboard position ended up on . + * + * isClosing is scoped to this one call rather than the whole method because everything + * above it (the wrapper refocus in particular) still needs the real state. The reset runs + * in a finally: if setSearchValue() ever threw, a stuck flag would silently stop the + * highlight coming back after *every* later filter clear, which is far harder to diagnose + * than the exception itself. + */ + this.isClosing = true; + try { + this.setSearchValue(''); + } finally { + this.isClosing = false; + } + + /** + * From here until the next open, no server-search announcement may reach the live region: + * the dropdown the messages would describe is gone. Closing spoke twice for an interaction + * the user never made - the reset above schedules a fetch of its own, which said + * loadingText one searchDelay after the dropbox had closed and then the result count when + * the host responded. The local path already refuses to announce a reset it performed + * itself (announceSearchResults); this flag is the same rule for the server path. + * + * A flag set for the whole closed period, rather than one latched onto the scheduled + * fetch, because the close cannot see everything that is still going to speak: + * setSearchValue('') early-returns when the user already emptied the box (leaving *their* + * pending fetch to fire after the close), and a response to an earlier search can land + * mid hide-transition, while isOpened() is still true. openDropbox() lifts the silence, + * so it cannot leak into the next open either. + * + * The reset fetch itself is deliberately left running - it is what restores the + * unfiltered list for the next open, since opening does not search. + */ + if (this.hasServerSearch) { + this.isSilentServerSearch = true; + } } afterHidePopper() { const isSilent = this.isSilentClose; @@ -3372,7 +3893,14 @@ class VirtualSelect { if (!isAllSelected && this.selectAllOnlyVisible && this.searchValue !== '' && (this.visibleOptionsCount > 0 || this.searchValue === '')) { isAllVisibleSelected = this.isAllOptionsSelected(true); } - DomUtils.toggleClass(this.$toggleAllCheckbox, 'checked', isAllSelected || isAllVisibleSelected); + const isChecked = isAllSelected || isAllVisibleSelected; + DomUtils.toggleClass(this.$toggleAllCheckbox, 'checked', isChecked); + /** + * Mirror the visual checked state onto the role="checkbox" host. This is the single + * point every selection path funnels through (select all, deselect all, per-option + * clicks, group toggles, setValue, reset), so the exposed state cannot drift. + */ + DomUtils.setAria(this.$toggleAllButton, 'checked', isChecked); this.isAllSelected = isAllSelected; } isAllOptionsSelected(visibleOnly) { @@ -3420,7 +3948,7 @@ class VirtualSelect { selectedValues, selectAllOnlyVisible } = this; - const valuesMapping = {}; + const valuesMapping = Object.create(null); const { removeItemFromArray } = Utils; @@ -3465,7 +3993,15 @@ class VirtualSelect { this.toggleOptionSelectedState($ele, isSelected); } toggleFocusedProp(index, isFocused = false) { - if (this.focusedOptionIndex) { + /** + * Explicitly against null, not truthiness. focusedOptionIndex comes from + * DomUtils.getData($ele, 'index') with no type, so today it is the *string* "0" and a + * truthiness test happens to pass for the first option. Normalise it to a number anywhere + * and index 0 would stop being cleared, so its `isFocused` prop would survive - and + * renderOptions() re-applies `.focused` and tabindex="0" from that prop, bringing the + * stale highlight back through the data path on the next render. + */ + if (this.focusedOptionIndex !== null && this.focusedOptionIndex !== undefined) { this.setOptionProp(this.focusedOptionIndex, 'isFocused', false); } this.setOptionProp(index, 'isFocused', isFocused); @@ -3494,7 +4030,18 @@ class VirtualSelect { }); this.afterValueSet(); if (formReset) { + /** + * A native form reset clears the error state, not just the colour that showed it. + * + * Removing `has-error` alone left aria-invalid="true" on the combobox and + * aria-describedby pointing at an error element that still held its text - so the control + * stayed announced as invalid, describing a message the user could no longer see, with no + * interaction able to clear it. setErrorMessage('') empties the text and drops + * aria-describedby, and does not announce (it only announces a non-empty message). + */ DomUtils.removeClass(this.$allWrappers, 'has-error'); + DomUtils.toggleAria(this.$allWrappers, 'invalid', false); + this.setErrorMessage(''); } DomUtils.dispatchEvent(this.$ele, 'reset'); } @@ -3524,6 +4071,8 @@ class VirtualSelect { removeNewOption() { const newOption = this.getNewOption(); if (newOption) { + /** removes a row from the filtered set */ + this.ariaMetadataDirty = true; this.removeOption(newOption.index); } } @@ -3643,6 +4192,17 @@ class VirtualSelect { serverSearch() { DomUtils.removeClass(this.$allWrappers, 'has-no-search-results'); DomUtils.addClass(this.$allWrappers, 'server-searching'); + + /** + * The spinner is a visual-only cue; announce that a fetch is in flight - but only for a + * dropdown the user can see. The silent flag covers the closed period (see closeDropbox); + * isOpened() covers fetches the component issued on its own while closed, such as the + * search reset showOptionsOnlyOnSearch forces during construction, which otherwise spoke + * loadingText on a page the user had not touched yet. + */ + if (this.isInitialized && !this.isSilentServerSearch && this.isOpened()) { + this.announce(this.loadingText); + } this.setSelectedOptions(); this.onServerSearch(this.searchValue, this); } @@ -3677,18 +4237,67 @@ class VirtualSelect { return true; } let hasError = false; + let errorText = ''; const { selectedValues, minValues } = this; - if (this.required && (Utils.isEmpty(selectedValues) || (/** required minium options not selected */ - this.multiple && minValues && selectedValues.length < minValues))) { - hasError = true; + if (this.required) { + if (Utils.isEmpty(selectedValues)) { + hasError = true; + errorText = this.requiredErrorText; + } else if (this.multiple && minValues && selectedValues.length < minValues) { + /** required minium options not selected */ + hasError = true; + errorText = Utils.getString(this.minValuesErrorText).replace('{count}', minValues); + } } DomUtils.toggleClass(this.$allWrappers, 'has-error', hasError); + + /** + * Previously the only signal was the `has-error` class recolouring the toggle button + * border: invisible to assistive technology and, being colour alone, a 1.4.1 failure. + * Expose the state (aria-invalid), give it a text message, point the combobox at that + * message (aria-describedby) and announce it. + */ + DomUtils.toggleAria(this.$allWrappers, 'invalid', hasError); + this.setErrorMessage(hasError ? errorText : ''); return !hasError; } + /** + * Show or clear the validation message and its association with the combobox. + * An empty message removes aria-describedby rather than pointing at empty text. + * + * @param {string} message + */ + setErrorMessage(message) { + if (!this.$errorMessage) { + return; + } + const text = message || ''; + this.$errorMessage.textContent = text; + DomUtils.toggleAria(this.$allWrappers, 'describedby', !!text, this.$errorMessage.id); + + /** + * The message is shown and exposed unconditionally, but only *announced* for something the + * user did. A live region is for status changes they caused. + * + * isInitialized keeps construction quiet: the initial setValueMethod() runs before that flag + * is set, so a page supplied with an invalid initial value used to load already speaking + * "Select at least 2 options". isRefreshingOptions keeps a programmatic data swap quiet: + * afterSetOptions() calls reset(), which validates, so replacing the options announced a + * failure for a field the user had never touched. + * + * Both are deliberately narrow. The interactive paths - the clear button, deselecting below + * minValues, and an explicit validate() from the application - must still announce, which is + * the whole point of routing validation through this region. + */ + if (text && this.isInitialized && !this.isRefreshingOptions) { + this.announce(text); + } + } + /** * setTimeout wrapper whose pending timers are tracked so they can be cleared on destroy(). * Prevents callbacks from running against a destroyed instance (stale DOM access / retention). @@ -3739,6 +4348,12 @@ class VirtualSelect { // Clear any other pending timeouts so their callbacks don't run on a destroyed instance this.clearManagedTimeouts(); + // Drop any queued scroll re-render so it cannot touch detached DOM + if (this.scrollAnimationFrame) { + cancelAnimationFrame(this.scrollAnimationFrame); + this.scrollAnimationFrame = null; + } + /** Remove all event listeners to prevent memory leaks and ensure proper cleanup */ this.removeEvents(); if (this.hasDropboxWrapper) { @@ -3767,8 +4382,20 @@ class VirtualSelect { if (!text || !this.enableSecureText) { return text; } - /** escape potentially harmful JavaScript so, label and value fields cannot trigger XSS */ - this.$secureText.nodeValue = Utils.replaceDoubleQuotesWithHTML(text); + + /** + * escape potentially harmful markup so label/value/description cannot trigger XSS. + * + * Quotes are deliberately *not* rewritten here. They were, and the text node's innerHTML + * then escaped the `&` that introduced - so `The "City" of Light` used to be stored as + * `The &quot;City&quot; of Light`, shown to the user as `The "City" of + * Light`, and made unsearchable, because labelNormalized derives from the stored text. + * Quotes only need escaping inside an attribute, and that now happens at each attribute + * boundary instead (data-value in renderOptions, DomUtils.getAttributesText) - which also + * covers the sinks this pre-escaping never reached, such as an attribute written while + * enableSecureText is off. + */ + this.$secureText.nodeValue = text; return this.$secureDiv.innerHTML; } @@ -3789,9 +4416,87 @@ class VirtualSelect { // eslint-disable-next-line no-console console.warn('[virtual-select] Option text (label, value, description) and any `customData` used in ' + 'markup are rendered as HTML and are NOT escaped because `enableSecureText` is disabled ' + '(the default, kept off for performance on large datasets). If any option text can come ' + 'from untrusted input, set `enableSecureText: true` to prevent XSS. ' + 'Docs: https://sa-si-dev.github.io/virtual-select/#/properties'); } + + /** + * Write a message into the instance's polite live region (WCAG 4.1.3 Status Messages). + * + * Identical consecutive messages are intentionally left alone: re-writing the same text + * produces no DOM mutation, so assistive technology does not repeat "No results found" + * on every further keystroke that still matches nothing. + * + * @param {string} message + */ + announce(message) { + if (!this.$liveRegion) { + return; + } + + /** + * Reduced to plain text because the region is written with textContent, so whatever is put + * there is read out literally. A single select announces the chosen label, and a label can + * carry both escaping and markup: with enableSecureText on the region said + * "Tom & Jerry selected", and decoding alone would only have turned that into + * " France selected". Neither is speech. Messages the component composes + * itself contain no markup, so this is a no-op for them. + */ + const text = Utils.getPlainText(message || ''); + if (this.$liveRegion.textContent !== text) { + this.$liveRegion.textContent = text; + } + } + + /** + * Message describing how many options the current filter matched. + * @returns {string} + */ + getResultsCountMessage() { + const count = this.filteredOptionsCount || 0; + if (count === 0) { + return this.noSearchResultsText; + } + return `${count} ${count === 1 ? this.searchResultText : this.searchResultsText}`; + } + + /** + * Message describing the current selection. + * @returns {string} + */ + getSelectionMessage() { + const count = this.selectedValues.length; + if (count === 0) { + return this.noOptionsSelectedText; + } + if (this.multiple) { + return `${count} ${count === 1 ? this.optionSelectedText : this.optionsSelectedText}`; + } + + /** option flags are updated before setValue(), so the label is already current */ + const label = this.getDisplayValue() || this.selectedValues[0]; + return `${label} ${this.selectedText}`; + } + + /** + * Announce the match count, but only while the user is actually searching. + * setSearchValue('') also runs on close and after a value is set; announcing there + * would read a stale count into the user's ear for an interaction they did not make. + */ + announceSearchResults() { + if (!this.isInitialized || !this.isOpened() || document.activeElement !== this.$searchInput) { + return; + } + this.announce(this.getResultsCountMessage()); + } toggleRequired(isRequired) { this.required = Utils.convertToBoolean(isRequired); this.$ele.required = this.required; + DomUtils.toggleAria(this.$allWrappers, 'required', this.required); + + /** dropping the requirement also drops any error it produced */ + if (!this.required) { + DomUtils.toggleClass(this.$allWrappers, 'has-error', false); + DomUtils.toggleAria(this.$allWrappers, 'invalid', false); + this.setErrorMessage(''); + } } toggleOptionSelectedState($ele, value) { let isSelected = value; @@ -3807,17 +4512,99 @@ class VirtualSelect { } DomUtils.toggleClass($ele, 'focused', isFocused); DomUtils.setAttr($ele, 'tabindex', isFocused ? '0' : '-1'); - if (document.activeElement !== this.$searchInput) { + + /** + * Only *taking* the highlight moves DOM focus. Clearing it used to focus the element it + * had just un-highlighted, which is either pointless (focusOption immediately focuses the + * new option anyway) or actively wrong: on close it pulled focus into a dropbox that is + * about to be hidden, fighting the wrapper refocus in closeDropbox(). + */ + if (isFocused && document.activeElement !== this.$searchInput) { $ele.focus(); } - if (isFocused) { - DomUtils.setAria(this.$wrapper, 'activedescendant', $ele.id); - // Also set aria-activedescendant on the listbox container for better screen reader support - DomUtils.setAria(this.$dropboxContainer, 'activedescendant', $ele.id); - } + + /** + * Publish the highlight on the elements that can carry it: the wrapper (the combobox) + * and the search input (a textbox, which also supports aria-activedescendant). It used + * to also go on $dropboxContainer, a plain div with no role, where aria-activedescendant + * is meaningless - and never on the search input, which is the element that actually + * holds focus while navigating. + */ + this.setActiveDescendant(isFocused ? $ele.id : ''); + } + + /** + * Point the combobox wrapper and the search input at the active option, or clear the + * reference. + * @param {string} optionId + */ + setActiveDescendant(optionId) { + DomUtils.toggleAria(this.$wrapper, 'activedescendant', !!optionId, optionId); + DomUtils.toggleAria(this.$searchInput, 'activedescendant', !!optionId, optionId); } /** static methods - start */ + + /** + * Set page-level default props applied to every instance created afterwards. + * + * The motivating case is security: option text is interpolated into innerHTML and is only + * escaped when `enableSecureText` is on, which it is not by default (escaping costs per + * option, and large trusted lists should not pay for it). A host that does render + * untrusted option text can turn escaping on once here rather than at every call site: + * + * VirtualSelect.setGlobalDefaults({ enableSecureText: true }); + * + * These are defaults, not overrides: an instance passing the prop explicitly still wins, + * so a host forwarding `enableSecureText` on every init must stop doing so (or forward + * `true`) for this to take effect. Calls merge, so features can be configured separately. + * Only instances created after the call are affected. + * + * @param {Partial} props + */ + static setGlobalDefaults(props) { + /** + * A non-object is ignored, not treated as "clear": a host forwarding an accidentally + * unset config variable would otherwise silently turn a page-wide security policy off. + * Clearing is an explicit act - resetGlobalDefaults(). A key can still be cleared + * individually by passing it with the value `undefined`, which setDefaultProps() + * treats as "not supplied". + */ + if (!props || typeof props !== 'object') { + return; + } + + /** `ele` and `options` are per-instance by nature and would alias state across instances */ + const safeProps = { + ...props + }; + delete safeProps.ele; + delete safeProps.options; + VirtualSelect.globalDefaults = { + ...VirtualSelect.globalDefaults, + ...safeProps + }; + } + + /** + * Drop every page-level default, restoring the built-in ones for instances created + * afterwards. The explicit counterpart to setGlobalDefaults(), which only ever merges. + */ + static resetGlobalDefaults() { + VirtualSelect.globalDefaults = {}; + } + + /** + * Currently active page-level defaults. + * A copy, so callers cannot mutate the live object. + * + * @returns {Partial} + */ + static getGlobalDefaults() { + return { + ...VirtualSelect.globalDefaults + }; + } static init(options) { let $eleArray = options.ele; if (!$eleArray) { @@ -4048,6 +4835,9 @@ VirtualSelect.lastInteractedInstance = null; // Ensures the "enableSecureText disabled" warning is logged at most once per page VirtualSelect.secureTextWarningShown = false; +// Page-level default props, applied under per-instance options (see setGlobalDefaults) +VirtualSelect.globalDefaults = {}; + /** polyfill to fix an issue in ie browser */ if (typeof NodeList !== 'undefined' && NodeList.prototype && !NodeList.prototype.forEach) { NodeList.prototype.forEach = Array.prototype.forEach; diff --git a/dist/virtual-select.min.css b/dist/virtual-select.min.css index 29fc53e..fb800b3 100644 --- a/dist/virtual-select.min.css +++ b/dist/virtual-select.min.css @@ -1,9 +1,9 @@ /*! - * Virtual Select v1.3.0 + * Virtual Select v1.4.0 * https://sa-si-dev.github.io/virtual-select * Licensed under MIT (https://github.com/sa-si-dev/virtual-select/blob/master/LICENSE) */ -@keyframes vscomp-animation-spin{to{transform:rotateZ(360deg)}}.vscomp-popup-active{overflow:hidden !important}.vscomp-ele{display:inline-block;max-width:250px;width:100%}.vscomp-wrapper{color:#333;display:inline-flex;flex-wrap:wrap;font-family:sans-serif;font-size:14px;position:relative;text-align:left;width:100%}.vscomp-wrapper *,.vscomp-wrapper *::before,.vscomp-wrapper *::after{box-sizing:border-box}.vscomp-wrapper:focus{outline:none}.vscomp-dropbox-wrapper{left:0;position:absolute;top:0}.vscomp-toggle-button{align-items:center;background-color:#fff;border:1px solid #ddd;cursor:pointer;display:flex;padding:7px 30px 7px 10px;position:relative;width:100%}.vscomp-value{height:20px;line-height:20px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vscomp-arrow{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;width:30px}.vscomp-arrow::after{transform:rotate(45deg);border:1px solid rgba(0,0,0,0);border-bottom-color:#111;border-right-color:#111;content:"";height:8px;margin-top:-6px;width:8px}.vscomp-clear-icon{height:12px;position:relative;width:12px}.vscomp-clear-icon::before,.vscomp-clear-icon::after{background-color:#999;content:"";height:12px;left:5px;position:absolute;top:0;width:2px}.vscomp-clear-icon::before{transform:rotate(45deg)}.vscomp-clear-icon::after{transform:rotate(-45deg)}.vscomp-clear-icon:hover::before,.vscomp-clear-icon:hover::after{background:#333}.vscomp-clear-button{align-items:center;border-radius:50%;display:none;height:24px;justify-content:center;margin-top:-12px;position:absolute;right:30px;top:50%;width:24px}.vscomp-clear-button:hover{background:#ccc}.vscomp-clear-button:hover .vscomp-clear-icon::before,.vscomp-clear-button:hover .vscomp-clear-icon::after{background-color:#333}.vscomp-dropbox-close-button{align-items:center;background-color:#fff;border-radius:50%;bottom:-48px;cursor:pointer;display:none;height:40px;justify-content:center;left:50%;margin-left:-20px;position:absolute;width:40px}.vscomp-value-tag.more-value-count{white-space:nowrap}.vscomp-dropbox-container{width:100%;z-index:2}.vscomp-dropbox{background-color:#fff;width:100%}.vscomp-options-container{max-height:210px;overflow:auto;position:relative}.vscomp-options-bottom-freezer{bottom:0;height:2px;left:0;position:absolute;right:0}.vscomp-option{align-items:center;cursor:pointer;display:flex;flex-wrap:wrap;height:40px;padding:0 15px;position:relative}.vscomp-option.selected{background-color:#eee}.vscomp-option.focused{background-color:#ccc}.vscomp-option.disabled{cursor:default;opacity:.5}.vscomp-option.group-title .vscomp-option-text{cursor:default;opacity:.6}.vscomp-option.group-title.selected{background-color:rgba(0,0,0,0)}.vscomp-option.group-option{padding-left:30px}.vscomp-new-option-icon{height:30px;position:absolute;right:0;top:0;width:30px}.vscomp-new-option-icon::before{border:15px solid #512da8;border-bottom-color:rgba(0,0,0,0);border-left-color:rgba(0,0,0,0);content:"";position:absolute;right:0;top:0}.vscomp-new-option-icon::after{align-items:center;color:#fff;content:"+";display:flex;font-size:18px;height:15px;justify-content:center;position:absolute;right:1px;top:0;width:15px}.vscomp-option-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;-webkit-user-select:none;user-select:none;width:100%}.vscomp-option-description{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#666;font-size:13px;line-height:15px;width:100%}.vscomp-search-container{align-items:center;border-bottom:1px solid #ddd;display:flex;height:40px;padding:0 5px 0 15px;position:relative}.vscomp-search-label,.vscomp-live-region,.vscomp-dropbox-container-top,.vscomp-dropbox-container-bottom{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.vscomp-search-input{background-color:rgba(0,0,0,0);border:0;color:inherit;font-size:15px;height:38px;padding:10px 0;width:calc(100% - 30px)}.vscomp-search-input:focus{outline:none}.vscomp-search-clear{align-items:center;color:#999;cursor:pointer;display:flex;font-size:25px;height:30px;justify-content:center;-webkit-user-select:none;user-select:none;visibility:hidden;width:30px}.vscomp-search-clear:hover{color:inherit}.vscomp-no-options,.vscomp-no-search-results{align-items:center;display:none;justify-content:center;padding:20px 10px}.vscomp-options-loader{display:none;padding:20px 0;text-align:center}.vscomp-options-loader::before{animation:vscomp-animation-spin .8s infinite linear;background-color:#fff;border-radius:50%;box-shadow:-4px -5px 3px -3px rgba(0,0,0,.3);content:"";display:inline-block;height:40px;opacity:.7;width:40px}.vscomp-ele[disabled]{cursor:not-allowed;-webkit-user-select:none;user-select:none}.vscomp-ele[disabled] .vscomp-wrapper{opacity:.7;pointer-events:none}.vscomp-wrapper .checkbox-icon{display:inline-flex;height:15px;margin-right:10px;position:relative;width:15px}.vscomp-wrapper .checkbox-icon::after{transition-duration:.2s;border:2px solid #888;content:"";display:inline-block;height:100%;width:100%}.vscomp-wrapper .checkbox-icon.checked::after{transform:rotate(45deg) translate(1px, -4px);border-color:#512da8;border-left-color:rgba(0,0,0,0);border-top-color:rgba(0,0,0,0);width:50%}.vscomp-wrapper.show-as-popup .vscomp-dropbox-container{align-items:center;background-color:rgba(0,0,0,.5);display:flex;height:100vh;justify-content:center;left:0;opacity:1;overflow:auto;padding:0 10px;position:fixed;top:0;width:100vw}.vscomp-wrapper.show-as-popup .vscomp-dropbox{margin-top:-24px;max-height:calc(80% - 48px);max-width:500px;position:relative;width:80%}.vscomp-wrapper.show-as-popup .vscomp-dropbox-close-button{display:flex}.vscomp-wrapper.popup-position-left .vscomp-dropbox-container{justify-content:flex-start}.vscomp-wrapper.popup-position-right .vscomp-dropbox-container{justify-content:flex-end}.vscomp-wrapper.has-select-all .vscomp-toggle-all-button{align-items:center;cursor:pointer;display:flex}.vscomp-wrapper.has-select-all .vscomp-search-input,.vscomp-wrapper.has-select-all .vscomp-toggle-all-label{width:calc(100% - 55px)}.vscomp-wrapper.has-select-all .vscomp-toggle-all-label{display:none}.vscomp-wrapper:not(.has-search-input) .vscomp-toggle-all-button{width:100%}.vscomp-wrapper:not(.has-search-input) .vscomp-toggle-all-label{display:inline-block}.vscomp-wrapper.multiple .vscomp-option .vscomp-option-text{width:calc(100% - 25px)}.vscomp-wrapper.multiple .vscomp-option .vscomp-option-description{padding-left:25px}.vscomp-wrapper.multiple .vscomp-option.selected .checkbox-icon::after{transform:rotate(45deg) translate(1px, -4px);border-color:#512da8;border-left-color:rgba(0,0,0,0);border-top-color:rgba(0,0,0,0);width:50%}.vscomp-wrapper.focused .vscomp-toggle-button,.vscomp-wrapper:focus .vscomp-toggle-button{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2)}.vscomp-wrapper.closed .vscomp-dropbox-container,.vscomp-wrapper.closed.vscomp-dropbox-wrapper{display:none}.vscomp-wrapper:not(.has-value) .vscomp-value{opacity:.5}.vscomp-wrapper.has-clear-button.has-value .vscomp-clear-button{display:flex}.vscomp-wrapper.has-clear-button .vscomp-toggle-button{padding-right:54px}.vscomp-wrapper.has-no-options .vscomp-options-container,.vscomp-wrapper.has-no-search-results .vscomp-options-container{display:none}.vscomp-wrapper.has-no-options .vscomp-no-options{display:flex}.vscomp-wrapper.has-no-search-results .vscomp-no-search-results{display:flex}.vscomp-wrapper.has-search-value .vscomp-search-clear{visibility:visible}.vscomp-wrapper.has-no-options .vscomp-toggle-all-button{opacity:.5;pointer-events:none}.vscomp-wrapper.keep-always-open .vscomp-toggle-button{padding-right:24px}.vscomp-wrapper.keep-always-open .vscomp-clear-button{right:5px}.vscomp-wrapper.keep-always-open .vscomp-arrow{display:none}.vscomp-wrapper.keep-always-open .vscomp-dropbox-container{position:relative;z-index:1}.vscomp-wrapper.keep-always-open .vscomp-dropbox{transition-duration:0s;border:1px solid #ddd;box-shadow:none}.vscomp-wrapper.keep-always-open.focused,.vscomp-wrapper.keep-always-open:focus,.vscomp-wrapper.keep-always-open:hover{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2)}.vscomp-wrapper.server-searching .vscomp-options-list{display:none}.vscomp-wrapper.server-searching .vscomp-options-loader{display:block}.vscomp-wrapper.has-error .vscomp-toggle-button{border-color:#b00020}.vscomp-wrapper.show-value-as-tags .vscomp-toggle-button{padding:4px 22px 0 10px}.vscomp-wrapper.show-value-as-tags .vscomp-value{display:flex;flex-wrap:wrap;height:auto;min-height:28px;overflow:auto;text-overflow:unset;white-space:normal}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;align-items:center;border:1px solid #ddd;border-radius:20px;display:inline-flex;font-size:12px;line-height:16px;margin:0 4px 4px 0;max-width:100%;padding:2px 3px 2px 8px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag.more-value-count{padding-right:8px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:calc(100% - 20px)}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-clear-button{align-items:center;display:flex;height:20px;justify-content:center;width:20px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-clear-button .vscomp-clear-icon{transform:scale(0.8)}.vscomp-wrapper.show-value-as-tags .vscomp-arrow{height:34px}.vscomp-wrapper.show-value-as-tags .vscomp-clear-button{margin-top:0;top:5px}.vscomp-wrapper.show-value-as-tags.has-value .vscomp-arrow{display:none}.vscomp-wrapper.show-value-as-tags.has-value .vscomp-clear-button{right:2px}.vscomp-wrapper.show-value-as-tags:not(.has-value) .vscomp-toggle-button{padding-bottom:2px}.vscomp-wrapper.show-value-as-tags:not(.has-value) .vscomp-value{align-items:center;padding-bottom:3px}.vscomp-wrapper.text-direction-rtl{direction:rtl}.vscomp-wrapper.text-direction-rtl .vscomp-toggle-button{padding:7px 10px 7px 30px}.vscomp-wrapper.text-direction-rtl .vscomp-arrow{left:0;right:auto}.vscomp-wrapper.text-direction-rtl .vscomp-clear-button{left:30px;right:auto !important}.vscomp-wrapper.text-direction-rtl .checkbox-icon{margin-left:10px;margin-right:0}.vscomp-wrapper.text-direction-rtl .checkbox-icon.checked::after{transform:rotate(45deg) translate(-4px, 1px)}.vscomp-wrapper.text-direction-rtl .vscomp-search-container{padding:0 15px 0 5px}.vscomp-wrapper.text-direction-rtl .vscomp-toggle-all-label{text-align:right}.vscomp-wrapper.text-direction-rtl .vscomp-option{text-align:right}.vscomp-wrapper.text-direction-rtl .vscomp-option.group-option{padding-right:30px}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon{left:0;right:auto}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon::before{border-left-color:#512da8;border-right-color:rgba(0,0,0,0)}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon::after{left:1px;right:auto}.vscomp-wrapper.text-direction-rtl.multiple .vscomp-option.selected .checkbox-icon::after{transform:rotate(45deg) translate(-4px, 1px)}.vscomp-wrapper.text-direction-rtl.has-clear-button .vscomp-toggle-button{padding-left:54px}.vscomp-wrapper.text-direction-rtl.keep-always-open .vscomp-toggle-button{padding-left:24px}.vscomp-wrapper.text-direction-rtl.keep-always-open .vscomp-clear-button{left:5px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-toggle-button{padding:4px 10px 0 22px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-value-tag{margin:0 0 4px 4px;padding:2px 8px 2px 3px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-value-tag.more-value-count{padding-left:8px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags.has-value .vscomp-clear-button{left:2px} +@keyframes vscomp-animation-spin{to{transform:rotateZ(360deg)}}.vscomp-popup-active{overflow:hidden !important}.vscomp-ele{display:inline-block;max-width:250px;width:100%}.vscomp-wrapper{color:#333;display:inline-flex;flex-wrap:wrap;font-family:sans-serif;font-size:14px;position:relative;text-align:left;width:100%}.vscomp-wrapper *,.vscomp-wrapper *::before,.vscomp-wrapper *::after{box-sizing:border-box}.vscomp-wrapper:focus{outline:none}.vscomp-dropbox-wrapper{left:0;position:absolute;top:0}.vscomp-toggle-button{align-items:center;background-color:#fff;border:1px solid #ddd;cursor:pointer;display:flex;padding:7px 30px 7px 10px;position:relative;width:100%}.vscomp-value{height:20px;line-height:20px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vscomp-arrow{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;width:30px}.vscomp-arrow::after{transform:rotate(45deg);border:1px solid rgba(0,0,0,0);border-bottom-color:#111;border-right-color:#111;content:"";height:8px;margin-top:-6px;width:8px}.vscomp-clear-icon{height:12px;position:relative;width:12px}.vscomp-clear-icon::before,.vscomp-clear-icon::after{background-color:#999;content:"";height:12px;left:5px;position:absolute;top:0;width:2px}.vscomp-clear-icon::before{transform:rotate(45deg)}.vscomp-clear-icon::after{transform:rotate(-45deg)}.vscomp-clear-icon:hover::before,.vscomp-clear-icon:hover::after{background:#333}.vscomp-clear-button{align-items:center;border-radius:50%;display:none;height:24px;justify-content:center;margin-top:-12px;position:absolute;right:30px;top:50%;width:24px}.vscomp-clear-button:hover{background:#ccc}.vscomp-clear-button:hover .vscomp-clear-icon::before,.vscomp-clear-button:hover .vscomp-clear-icon::after{background-color:#333}.vscomp-dropbox-close-button{align-items:center;background-color:#fff;border-radius:50%;bottom:-48px;cursor:pointer;display:none;height:40px;justify-content:center;left:50%;margin-left:-20px;position:absolute;width:40px}.vscomp-value-tag.more-value-count{white-space:nowrap}.vscomp-dropbox-container{width:100%;z-index:2}.vscomp-dropbox{background-color:#fff;width:100%}.vscomp-options-container{max-height:210px;overflow:auto;position:relative}.vscomp-options-bottom-freezer{bottom:0;height:2px;left:0;position:absolute;right:0}.vscomp-option{align-items:center;cursor:pointer;display:flex;flex-wrap:wrap;height:40px;padding:0 15px;position:relative}.vscomp-option.selected{background-color:#eee}.vscomp-option.focused{background-color:#ccc}.vscomp-option.disabled{cursor:default;opacity:.5}.vscomp-option.group-title .vscomp-option-text{cursor:default;opacity:.6}.vscomp-option.group-title.selected{background-color:rgba(0,0,0,0)}.vscomp-option.group-option{padding-left:30px}.vscomp-new-option-icon{height:30px;position:absolute;right:0;top:0;width:30px}.vscomp-new-option-icon::before{border:15px solid #512da8;border-bottom-color:rgba(0,0,0,0);border-left-color:rgba(0,0,0,0);content:"";position:absolute;right:0;top:0}.vscomp-new-option-icon::after{align-items:center;color:#fff;content:"+";display:flex;font-size:18px;height:15px;justify-content:center;position:absolute;right:1px;top:0;width:15px}.vscomp-option-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;-webkit-user-select:none;user-select:none;width:100%}.vscomp-option-description{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#666;font-size:13px;line-height:15px;width:100%}.vscomp-search-container{align-items:center;border-bottom:1px solid #ddd;display:flex;height:40px;padding:0 5px 0 15px;position:relative}.vscomp-search-label,.vscomp-live-region,.vscomp-dropbox-container-top,.vscomp-dropbox-container-bottom{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.vscomp-search-input{background-color:rgba(0,0,0,0);border:0;color:inherit;font-size:15px;height:38px;padding:10px 0;width:calc(100% - 30px)}.vscomp-search-input:focus{outline:none}.vscomp-search-clear{align-items:center;color:#999;cursor:pointer;display:flex;font-size:25px;height:30px;justify-content:center;-webkit-user-select:none;user-select:none;visibility:hidden;width:30px}.vscomp-search-clear:hover{color:inherit}.vscomp-error-message{align-items:flex-start;color:#b00020;display:none;font-size:13px;gap:4px;line-height:1.4;padding-top:4px;width:100%}.vscomp-error-message::before{content:"\26A0";flex:none;font-size:1.1em;line-height:1.2}.vscomp-no-options,.vscomp-no-search-results{align-items:center;display:none;justify-content:center;padding:20px 10px}.vscomp-options-loader{display:none;padding:20px 0;text-align:center}.vscomp-options-loader::before{animation:vscomp-animation-spin .8s infinite linear;background-color:#fff;border-radius:50%;box-shadow:-4px -5px 3px -3px rgba(0,0,0,.3);content:"";display:inline-block;height:40px;opacity:.7;width:40px}.vscomp-ele[disabled]{cursor:not-allowed;-webkit-user-select:none;user-select:none}.vscomp-ele[disabled] .vscomp-wrapper{opacity:.7;pointer-events:none}.vscomp-wrapper .checkbox-icon{display:inline-flex;height:15px;margin-right:10px;position:relative;width:15px}.vscomp-wrapper .checkbox-icon::after{transition-duration:.2s;border:2px solid #888;content:"";display:inline-block;height:100%;width:100%}.vscomp-wrapper .checkbox-icon.checked::after{transform:rotate(45deg) translate(1px, -4px);border-color:#512da8;border-left-color:rgba(0,0,0,0);border-top-color:rgba(0,0,0,0);width:50%}.vscomp-wrapper.show-as-popup .vscomp-dropbox-container{align-items:center;background-color:rgba(0,0,0,.5);display:flex;height:100vh;justify-content:center;left:0;opacity:1;overflow:auto;padding:0 10px;position:fixed;top:0;width:100vw}.vscomp-wrapper.show-as-popup .vscomp-dropbox{margin-top:-24px;max-height:calc(80% - 48px);max-width:500px;position:relative;width:80%}.vscomp-wrapper.show-as-popup .vscomp-dropbox-close-button{display:flex}.vscomp-wrapper.popup-position-left .vscomp-dropbox-container{justify-content:flex-start}.vscomp-wrapper.popup-position-right .vscomp-dropbox-container{justify-content:flex-end}.vscomp-wrapper.has-select-all .vscomp-toggle-all-button{align-items:center;cursor:pointer;display:flex;min-height:24px;min-width:24px}.vscomp-wrapper.has-select-all .vscomp-search-input,.vscomp-wrapper.has-select-all .vscomp-toggle-all-label{width:calc(100% - 55px)}.vscomp-wrapper.has-select-all .vscomp-toggle-all-label{display:none}.vscomp-wrapper:not(.has-search-input) .vscomp-toggle-all-button{width:100%}.vscomp-wrapper:not(.has-search-input) .vscomp-toggle-all-label{display:inline-block}.vscomp-wrapper.multiple .vscomp-option .vscomp-option-text{width:calc(100% - 25px)}.vscomp-wrapper.multiple .vscomp-option .vscomp-option-description{padding-left:25px}.vscomp-wrapper.multiple .vscomp-option.selected .checkbox-icon::after{transform:rotate(45deg) translate(1px, -4px);border-color:#512da8;border-left-color:rgba(0,0,0,0);border-top-color:rgba(0,0,0,0);width:50%}.vscomp-wrapper.focused .vscomp-toggle-button,.vscomp-wrapper:focus .vscomp-toggle-button{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2)}.vscomp-wrapper.closed .vscomp-dropbox-container,.vscomp-wrapper.closed.vscomp-dropbox-wrapper{display:none}.vscomp-wrapper:not(.has-value) .vscomp-value{opacity:.5}.vscomp-wrapper.has-clear-button.has-value .vscomp-clear-button{display:flex}.vscomp-wrapper.has-clear-button .vscomp-toggle-button{padding-right:54px}.vscomp-wrapper.has-no-options .vscomp-options-container,.vscomp-wrapper.has-no-search-results .vscomp-options-container{display:none}.vscomp-wrapper.has-no-options .vscomp-no-options{display:flex}.vscomp-wrapper.has-no-search-results .vscomp-no-search-results{display:flex}.vscomp-wrapper.has-search-value .vscomp-search-clear{visibility:visible}.vscomp-wrapper.has-no-options .vscomp-toggle-all-button{opacity:.5;pointer-events:none}.vscomp-wrapper.keep-always-open .vscomp-toggle-button{padding-right:24px}.vscomp-wrapper.keep-always-open .vscomp-clear-button{right:5px}.vscomp-wrapper.keep-always-open .vscomp-arrow{display:none}.vscomp-wrapper.keep-always-open .vscomp-dropbox-container{position:relative;z-index:1}.vscomp-wrapper.keep-always-open .vscomp-dropbox{transition-duration:0s;border:1px solid #ddd;box-shadow:none}.vscomp-wrapper.keep-always-open.focused,.vscomp-wrapper.keep-always-open:focus,.vscomp-wrapper.keep-always-open:hover{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2)}.vscomp-wrapper.server-searching .vscomp-options-list{display:none}.vscomp-wrapper.server-searching .vscomp-options-loader{display:block}.vscomp-wrapper.has-error .vscomp-toggle-button{border-color:#b00020}.vscomp-wrapper.has-error~.vscomp-error-message{display:flex}.vscomp-wrapper.show-value-as-tags .vscomp-toggle-button{padding:4px 22px 0 10px}.vscomp-wrapper.show-value-as-tags .vscomp-value{display:flex;flex-wrap:wrap;height:auto;min-height:28px;overflow:auto;text-overflow:unset;white-space:normal}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;align-items:center;border:1px solid #ddd;border-radius:20px;display:inline-flex;font-size:12px;line-height:16px;margin:0 4px 4px 0;max-width:100%;padding:2px 3px 2px 8px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag.more-value-count{padding-right:8px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:calc(100% - 24px)}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-clear-button{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-clear-button .vscomp-clear-icon{transform:scale(0.8)}.vscomp-wrapper.show-value-as-tags .vscomp-arrow{height:34px}.vscomp-wrapper.show-value-as-tags .vscomp-clear-button{margin-top:0;top:5px}.vscomp-wrapper.show-value-as-tags.has-value .vscomp-arrow{display:none}.vscomp-wrapper.show-value-as-tags.has-value .vscomp-clear-button{right:2px}.vscomp-wrapper.show-value-as-tags:not(.has-value) .vscomp-toggle-button{padding-bottom:2px}.vscomp-wrapper.show-value-as-tags:not(.has-value) .vscomp-value{align-items:center;padding-bottom:3px}@media(prefers-reduced-motion: reduce){.vscomp-dropbox-container,.vscomp-dropbox,.vscomp-wrapper .vscomp-toggle-button,.vscomp-dropbox-wrapper{transition-duration:0s !important}}.vscomp-wrapper.text-direction-rtl{direction:rtl}.vscomp-wrapper.text-direction-rtl .vscomp-toggle-button{padding:7px 10px 7px 30px}.vscomp-wrapper.text-direction-rtl .vscomp-arrow{left:0;right:auto}.vscomp-wrapper.text-direction-rtl .vscomp-clear-button{left:30px;right:auto !important}.vscomp-wrapper.text-direction-rtl .checkbox-icon{margin-left:10px;margin-right:0}.vscomp-wrapper.text-direction-rtl .checkbox-icon.checked::after{transform:rotate(45deg) translate(-4px, 1px)}.vscomp-wrapper.text-direction-rtl .vscomp-search-container{padding:0 15px 0 5px}.vscomp-wrapper.text-direction-rtl .vscomp-toggle-all-label{text-align:right}.vscomp-wrapper.text-direction-rtl .vscomp-option{text-align:right}.vscomp-wrapper.text-direction-rtl .vscomp-option.group-option{padding-right:30px}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon{left:0;right:auto}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon::before{border-left-color:#512da8;border-right-color:rgba(0,0,0,0)}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon::after{left:1px;right:auto}.vscomp-wrapper.text-direction-rtl.multiple .vscomp-option.selected .checkbox-icon::after{transform:rotate(45deg) translate(-4px, 1px)}.vscomp-wrapper.text-direction-rtl.has-clear-button .vscomp-toggle-button{padding-left:54px}.vscomp-wrapper.text-direction-rtl.keep-always-open .vscomp-toggle-button{padding-left:24px}.vscomp-wrapper.text-direction-rtl.keep-always-open .vscomp-clear-button{left:5px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-toggle-button{padding:4px 10px 0 22px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-value-tag{margin:0 0 4px 4px;padding:2px 8px 2px 3px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-value-tag.more-value-count{padding-left:8px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags.has-value .vscomp-clear-button{left:2px} /*! * Popover v1.0.13 * https://sa-si-dev.github.io/popover diff --git a/dist/virtual-select.min.js b/dist/virtual-select.min.js index 5ab3dec..d6ca8ea 100644 --- a/dist/virtual-select.min.js +++ b/dist/virtual-select.min.js @@ -1,5 +1,5 @@ /*! - * Virtual Select v1.3.0 + * Virtual Select v1.4.0 * https://sa-si-dev.github.io/virtual-select * Licensed under MIT (https://github.com/sa-si-dev/virtual-select/blob/master/LICENSE) - */!function(){"use strict";const e=/[^\p{L}\p{N}_]/gu;class t{static getString(e){return e||0===e?e.toString():""}static convertToBoolean(e,t=!1){let s;return s=!0===e||"true"===e||!1!==e&&"false"!==e&&t,s}static isEmpty(e){let t=!1;return e?Array.isArray(e)?0===e.length&&(t=!0):"object"==typeof e&&0===Object.keys(e).length&&(t=!0):t=!0,t}static isNotEmpty(e){return!t.isEmpty(e)}static normalizeValues(e){if(Array.isArray(e)){const t=new Array(e.length);for(let s=0;s!!e):[]}static getRandomInt(e,t=0){const s=Math.ceil(t),i=Math.floor(e);return Math.floor(Math.random()*(i-s-1))+s}static regexEscape(e){return e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}static normalizeString(t){return t.normalize("NFD").replace(e,"")}static willTextOverflow(e,t){const s=document.createElement("div");s.style.position="absolute",s.style.visibility="hidden",s.style.whiteSpace="nowrap",s.style.fontSize=window.getComputedStyle(e).fontSize,s.style.fontFamily=window.getComputedStyle(e).fontFamily,s.textContent=t,document.body.appendChild(s);const i=s.clientWidth;return document.body.removeChild(s),i>e.clientWidth}static replaceDoubleQuotesWithHTML(e){return e.replace(/"/g,""")}static containsHTML(e){return/<[a-z][\s\S]*>/i.test(e)}static containsHTMLorJS(e){return/<([a-z]+)[\s\S]*?>|on\w+="[^"]*"/i.test(e)}static sanitizeClassNames(e){return e?String(e).replace(/["<>]/g,""):e}static throttle(e,t){let s,i=null,o=[],n=0;function r(){const t=s,i=o;o=[],s=void 0,e.apply(t,i)}function a(...e){const a=Date.now(),l=t-(a-n);o=e,s=this,l<=0||l>t?(i&&(clearTimeout(i),i=null),n=a,r()):i||(i=setTimeout(()=>{n=Date.now(),i=null,r()},l))}return a.cancel=function(){i&&(clearTimeout(i),i=null),n=0,o=[],s=void 0},a}}class s{static addClass(e,t){if(!e)return;const i=t.split(" ");s.getElements(e).forEach(e=>{e.classList.add(...i)})}static removeClass(e,t){if(!e)return;const i=t.split(" ");s.getElements(e).forEach(e=>{e.classList.remove(...i)})}static toggleClass(e,t,i){if(!e)return;let o;void 0!==i&&(o=Boolean(i)),s.getElements(e).forEach(e=>{e.classList.toggle(t,o)})}static hasClass(e,t){return!!e&&e.classList.contains(t)}static hasEllipsis(e){return!!e&&e.scrollWidth>e.offsetWidth}static getData(e,t,s){if(!e)return;let i=e?e.dataset[t]:"";return"number"===s?i=parseFloat(i)||0:"true"===i?i=!0:"false"===i&&(i=!1),i}static setData(e,t,s){e&&(e.dataset[t]=s)}static setAttr(e,t,s){e&&e.setAttribute(t,s)}static setAttrFromEle(e,t,s,i){const o={};s.forEach(t=>{o[t]=e.getAttribute(t)}),s.forEach(e=>{const s=o[e];(s||-1!==i.indexOf(e)&&""===s)&&t.setAttribute(e,s)})}static setStyle(e,t,s){e&&(e.style[t]=s)}static setStyles(e,t){e&&t&&Object.keys(t).forEach(s=>{e.style[s]=t[s]})}static setAria(e,t,s){if(!e)return;let i=t;"role"!==i&&(i=`aria-${i}`),e.setAttribute(i,s)}static getElements(e){return e?void 0===e.forEach?[e]:e:[]}static getElementsBySelector(e="",t=void 0){let s;const i=void 0!==t?t:document;return""!==e&&(s=i.querySelectorAll(e)),void 0!==s?Array.from(s):[]}static addEvent(e,i,o,n){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{s.getElements(e).forEach(e=>{e.addEventListener(t,o,{capture:n})})})}static dispatchEvent(e,t,i=!1){if(!e)return;const o=s.getElements(e);setTimeout(()=>{o.forEach(e=>{e.dispatchEvent(new CustomEvent(t,{bubbles:i}))})},0)}static getAttributesText(e){let t="";return e?(Object.entries(e).forEach(([e,s])=>{void 0!==s&&(t+=` ${e}="${s}" `)}),t):t}static convertPropToDataAttr(e){return e?`data-${e}`.replace(/([A-Z])/g,"-$1").toLowerCase():""}static changeTabIndex(e,t){e?s.getElements(e).forEach(e=>{e.tabIndex=t}):console.log(e,"Invalid element provided.")}static removeEvent(e,t,i,o=!1){e&&s.getElements(e).forEach(e=>{e.removeEventListener(t,i,{capture:o})})}}const i={13:"onEnterPress",38:"onUpArrowPress",40:"onDownArrowPress",46:"onBackspaceOrDeletePress",8:"onBackspaceOrDeletePress"},o=["autofocus","disabled","multiple","required"],n=["autofocus","class","disabled","id","multiple","name","placeholder","required"];let r;const a=["additionalClasses","additionalDropboxClasses","additionalDropboxContainerClasses","additionalToggleButtonClasses","aliasKey","allOptionsSelectedText","allowNewOption","alwaysShowSelectedOptionsCount","alwaysShowSelectedOptionsLabel","ariaLabelledby","ariaLabelText","ariaLabelClearButtonText","ariaLabelTagClearButtonText","ariaLabelSearchClearButtonText","autoSelectFirstOption","clearButtonText","descriptionKey","disableAllOptionsSelectedText","disableOptionGroupCheckbox","disableSelectAll","disableValidation","dropboxWidth","dropboxWrapper","emptyValue","enableSecureText","focusSelectedOptionOnOpen","hasOptionDescription","hideClearButton","hideValueTooltipOnSelectAll","keepAlwaysOpen","labelKey","markSearchResults","maxValues","maxWidth","minValues","moreText","noOfDisplayValues","noOptionsText","noSearchResultsText","optionHeight","optionSelectedText","optionsCount","optionsSelectedText","popupDropboxBreakpoint","popupPosition","position","search","searchByStartsWith","searchDelay","searchFormLabel","searchGroup","searchNormalize","searchPlaceholderText","selectAllOnlyVisible","selectAllText","setValueAsArray","showDropboxAsPopup","showOptionsOnlyOnSearch","showSecureTextWarning","showSelectedOptionsFirst","showValueAsTags","silentInitialValueSet","textDirection","tooltipAlignment","tooltipFontSize","tooltipMaxWidth","updatePositionThrottle","useGroupValue","valueKey","zIndex"];class l{constructor(e){this.isDestroyed=!1;try{this.createSecureTextElements(),this.setProps(e),this.setDisabledOptions(e.disabledOptions),this.setOptions(e.options),this.warnIfSecureTextDisabled(),this.render()}catch(e){console.warn("Couldn't initiate Virtual Select"),console.error(e)}}render(){if(!this.$ele)return;const{uniqueId:e}=this;let i="vscomp-wrapper",o="vscomp-toggle-button";const n=this.showValueAsTags?"":this.getTooltipAttrText(this.placeholder,!0,!0),r=this.getTooltipAttrText(this.clearButtonText),a=this.ariaLabelledby?`aria-labelledby="${this.ariaLabelledby}"`:"",l=this.ariaLabelText?`aria-label="${this.ariaLabelText}"`:"",h=this.ariaLabelClearButtonText?`aria-label="${this.ariaLabelClearButtonText}"`:"";let p=!1;this.additionalClasses&&(i+=` ${t.sanitizeClassNames(this.additionalClasses)}`),this.additionalToggleButtonClasses&&(o+=` ${t.sanitizeClassNames(this.additionalToggleButtonClasses)}`),this.multiple&&(i+=" multiple",this.disableSelectAll||(i+=" has-select-all")),this.hideClearButton||(i+=" has-clear-button"),this.keepAlwaysOpen?(i+=" keep-always-open",p=!0):i+=" closed",this.showAsPopup&&(i+=" show-as-popup"),this.hasSearch&&(i+=" has-search-input"),this.showValueAsTags&&(i+=" show-value-as-tags"),this.textDirection&&(i+=` text-direction-${this.textDirection}`),this.popupPosition&&(i+=` popup-position-${this.popupPosition.toLowerCase()}`);const c=`
\n \n
\n
\n ${this.placeholder}\n
\n
\n
\n \n
\n
\n\n ${this.renderDropbox({wrapperClasses:i})}\n
`;this.$ele.innerHTML=c,this.$body=document.querySelector("body"),this.$wrapper=this.$ele.querySelector(".vscomp-wrapper"),this.hasDropboxWrapper?(this.$allWrappers=[this.$wrapper,this.$dropboxWrapper],this.$dropboxContainer=this.$dropboxWrapper.querySelector(".vscomp-dropbox-container"),s.addClass(this.$dropboxContainer,"pop-comp-wrapper")):(this.$allWrappers=[this.$wrapper],this.$dropboxContainer=this.$wrapper.querySelector(".vscomp-dropbox-container")),this.$toggleButton=this.$ele.querySelector(".vscomp-toggle-button"),this.$clearButton=this.$ele.querySelector(".vscomp-clear-button"),this.$valueText=this.$ele.querySelector(".vscomp-value"),this.$hiddenInput=this.$ele.querySelector(".vscomp-hidden-input"),this.$dropbox=this.$dropboxContainer.querySelector(".vscomp-dropbox"),this.$dropboxCloseButton=this.$dropboxContainer.querySelector(".vscomp-dropbox-close-button"),this.$dropboxContainerBottom=this.$dropboxContainer.querySelector(".vscomp-dropbox-container-bottom"),this.$dropboxContainerTop=this.$dropboxContainer.querySelector(".vscomp-dropbox-container-top"),this.$search=this.$dropboxContainer.querySelector(".vscomp-search-wrapper"),this.$optionsContainer=this.$dropboxContainer.querySelector(".vscomp-options-container"),this.$optionsList=this.$dropboxContainer.querySelector(".vscomp-options-list"),this.$options=this.$dropboxContainer.querySelector(".vscomp-options"),this.$noOptions=this.$dropboxContainer.querySelector(".vscomp-no-options"),this.$noSearchResults=this.$dropboxContainer.querySelector(".vscomp-no-search-results"),this.afterRenderWrapper()}renderDropbox({wrapperClasses:e}){const i="self"!==this.dropboxWrapper?document.querySelector(this.dropboxWrapper):null;let o="vscomp-dropbox";this.additionalDropboxClasses&&(o+=` ${t.sanitizeClassNames(this.additionalDropboxClasses)}`);let n="vscomp-dropbox-container";this.additionalDropboxContainerClasses&&(n+=` ${t.sanitizeClassNames(this.additionalDropboxContainerClasses)}`);const r=`
\n \n
\n
\n\n
\n
\n\n
\n
\n
\n
\n\n
\n
${this.noOptionsText}
\n
${this.noSearchResultsText}
\n\n \n
\n \n
`;if(i){const t=document.createElement("div");return this.$dropboxWrapper=t,this.hasDropboxWrapper=!0,t.innerHTML=r,i.appendChild(t),s.addClass(t,`vscomp-dropbox-wrapper ${e}`),this.keepAlwaysOpen||(s.setAttr(t,"tabindex","-1"),s.setAria(t,"hidden",!0)),""}return this.hasDropboxWrapper=!1,r}renderOptions(){this.calculateAriaMetadata();let e="";const s=this.getVisibleOptions();let i="",o="";const n=!(!this.markSearchResults||!this.searchValue);let r;const{labelRenderer:a,disableOptionGroupCheckbox:l,uniqueId:h,searchGroup:p}=this,c="function"==typeof a,{convertToBoolean:u}=t;let d="";if(n&&(r=new RegExp(`(${t.regexEscape(this.searchValue)})(?!([^<]+)?>)`,"gi")),this.multiple&&(i=''),this.allowNewOption){const e=this.getTooltipAttrText("New Option");o=``}s.forEach(s=>{const{index:v}=s;let b,m="vscomp-option";const f=this.getTooltipAttrText("",!0,!0);let g=i,S="",O="",x="",y="",$="-1";const w=u(s.isSelected);let C="";if(s.classNames&&(m+=` ${t.sanitizeClassNames(s.classNames)}`),s.isFocused&&($="0",m+=" focused"),s.isDisabled&&(m+=" disabled",C='aria-disabled="true"'),s.isGroupTitle&&(d=s.label,m+=" group-title",l?g="":this.multiple&&(y=`aria-label="${t.replaceDoubleQuotesWithHTML(t.getString(s.label))}, ${t.replaceDoubleQuotesWithHTML(t.getString(this.selectAllText))}"`)),w&&(m+=" selected"),s.isGroupOption){let e="";if(m+=" group-option",x=`data-group-index="${s.groupIndex}"`,s.customData){const i=this.secureText(t.getString(s.customData.group_name)),o=this.secureText(t.getString(s.customData.description));d=void 0!==s.customData.group_name?`${i}, `:"",e=void 0!==s.customData.description?` ${o},`:"",y=`aria-label="${d} ${s.label}, ${e}"`}else y=`aria-label="${d}, ${s.label}"`}b=c?a(s):s.label,s.description&&(O=`
${s.description}
`),s.isCurrentNew?(m+=" current-new",S+=o):!n||s.isGroupTitle&&!p||(b=b.replace(r,"$1"));let E="";this.ariaSetSize>0&&(E=`aria-setsize="${this.ariaSetSize}"`,s.filteredIndex&&(E+=` aria-posinset="${s.filteredIndex}"`)),e+=`
\n ${g}\n \n ${b}\n \n ${O}\n ${S}\n
`}),d="",this.$options.innerHTML=e,this.$visibleOptions=this.$options.querySelectorAll(".vscomp-option"),this.afterRenderOptions()}renderSearch(){if(!this.hasSearchContainer)return;let e="",t="";if(this.multiple&&!this.disableSelectAll&&(e=`\n \n ${this.selectAllText}\n `),this.hasSearch){const e=this.ariaLabelSearchClearButtonText?`aria-label="${this.ariaLabelSearchClearButtonText}"`:"";t=`\n \n ×`}const s=`
\n ${e}\n ${t}\n
`;this.$search.innerHTML=s,this.$searchInput=this.$dropboxContainer.querySelector(".vscomp-search-input"),this.$searchClear=this.$dropboxContainer.querySelector(".vscomp-search-clear"),this.$toggleAllButton=this.$dropboxContainer.querySelector(".vscomp-toggle-all-button"),this.$toggleAllCheckbox=this.$dropboxContainer.querySelector(".vscomp-toggle-all-checkbox"),this.addEvent(this.$searchInput,"input","onSearch"),this.addEvent(this.$searchInput,"change","preventPropagation"),this.addEvent(this.$searchClear,"click keydown","onSearchClear"),this.addEvent(this.$toggleAllButton,"click","onToggleAllOptions"),this.addEvent(this.$dropboxContainerBottom,"focus","onDropboxContainerTopOrBottomFocus"),this.addEvent(this.$dropboxContainerTop,"focus","onDropboxContainerTopOrBottomFocus")}addEvents(){this.addEvent(document,"click","onDocumentClick",!0),this.addEvent(this.$allWrappers,"keydown","onKeyDown"),this.addEvent(this.$toggleButton,"click keydown","onToggleButtonPress"),this.addEvent(this.$clearButton,"click keydown","onClearButtonClick"),this.addEvent(this.$dropboxContainer,"click","onDropboxContainerClick"),this.addEvent(this.$dropboxCloseButton,"click","onDropboxCloseButtonClick"),this.addEvent(this.$optionsContainer,"scroll","onOptionsScroll"),this.addEvent(this.$options,"click","onOptionsClick"),this.addEvent(this.$options,"mouseover","onOptionsMouseOver"),this.addEvent(this.$options,"touchmove","onOptionsTouchMove"),l.registerInstance(this)}addEvent(e,i,o,n=!1){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{const i=`${o}-${t}`;let r=this.events[i];r||(r=this[o].bind(this),this.events[i]=r),s.addEvent(e,t,r,n)})}removeEvents(){this.removeEvent(document,"click","onDocumentClick",!0),this.removeEvent(this.$allWrappers,"keydown","onKeyDown"),this.removeEvent(this.$toggleButton,"click keydown","onToggleButtonPress"),this.removeEvent(this.$clearButton,"click keydown","onClearButtonClick"),this.removeEvent(this.$dropboxContainer,"click","onDropboxContainerClick"),this.removeEvent(this.$dropboxCloseButton,"click","onDropboxCloseButtonClick"),this.removeEvent(this.$optionsContainer,"scroll","onOptionsScroll"),this.removeEvent(this.$options,"click","onOptionsClick"),this.removeEvent(this.$options,"mouseover","onOptionsMouseOver"),this.removeEvent(this.$options,"touchmove","onOptionsTouchMove"),this.$searchInput&&(this.removeEvent(this.$searchInput,"input","onSearch"),this.removeEvent(this.$searchInput,"change","preventPropagation"),this.$searchClear&&(this.removeEvent(this.$searchClear,"click","onSearchClear"),this.removeEvent(this.$searchClear,"keydown","onSearchClear"))),this.$toggleAllButton&&this.removeEvent(this.$toggleAllButton,"click","onToggleAllOptions"),this.$dropboxContainerBottom&&this.removeEvent(this.$dropboxContainerBottom,"focus","onDropboxContainerTopOrBottomFocus"),this.$dropboxContainerTop&&this.removeEvent(this.$dropboxContainerTop,"focus","onDropboxContainerTopOrBottomFocus")}removeEvent(e,i,o,n=!1){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{const i=`${o}-${t}`,r=this.events[i];r&&s.removeEvent(e,t,r,n)})}onDocumentClick(e){const t=e.target.closest(".vscomp-wrapper");if(!t)return void l.openInstances.forEach(e=>{const t=e;t.shouldFocusWrapperOnClose=!1,t.closeDropbox()});const s=t.parentElement.virtualSelect;s&&s!==this&&this.isOpened()&&!this.keepAlwaysOpen&&(this.shouldFocusWrapperOnClose=!1,this.closeDropbox())}onKeyDown(e){const t=e.which||e.keyCode,s=i[t];if(document.activeElement!==this.$searchInput||e.shiftKey||9!==t||this.multiple||(e.preventDefault(),this.focusFirstVisibleOption()),document.activeElement!==this.$toggleAllButton||13!==t){if(27===t||"Escape"===e.key){const e=this.showAsPopup?this.$wrapper:this.$dropboxWrapper;if(e&&(document.activeElement===e||e.contains(document.activeElement))&&!this.keepAlwaysOpen)return void this.closeDropbox()}s&&this[s](e)}else this.toggleAllOptions()}onEnterPress(e){e.preventDefault(),this.isOpened()?this.selectFocusedOption():!1===this.$ele.disabled&&this.openDropbox()}onDownArrowPress(e){document.activeElement!==this.$searchInput&&(e.preventDefault(),this.isOpened()?this.focusOption({direction:"next"}):this.openDropbox())}onUpArrowPress(e){document.activeElement!==this.$searchInput&&(e.preventDefault(),this.isOpened()?this.focusOption({direction:"previous"}):this.openDropbox())}onBackspaceOrDeletePress(e){e.target===this.$wrapper&&(e.preventDefault(),this.selectedValues.length>0&&this.reset())}onToggleButtonPress(e){if("keydown"===e.type){if("Enter"!==e.code&&"Space"!==e.code)return;e.preventDefault()}const t=e.target;if(t.closest(".vscomp-value-tag-clear-button"))return e.stopPropagation(),void this.removeValue(t.closest(".vscomp-value-tag"));t.closest(".toggle-button-child")||this.toggleDropbox()}onClearButtonClick(e){"click"===e.type?this.reset():"keydown"!==e.type||"Enter"!==e.code&&"Space"!==e.code||(e.stopPropagation(),this.reset())}onOptionsScroll(){this.setVisibleOptions(!0)}onOptionsClick(e){const t=e.target.closest(".vscomp-option");t&&!s.hasClass(t,"disabled")&&(s.hasClass(t,"group-title")?this.onGroupTitleClick(t):this.selectOption(t,{event:e}))}onGroupTitleClick(e){if(!e||!this.multiple||this.disableOptionGroupCheckbox)return;const t=!s.hasClass(e,"selected");this.toggleGroupTitleCheckbox(e,t),this.toggleGroupOptions(e,t)}onDropboxContainerClick(e){e.target.closest(".vscomp-dropbox")||this.closeDropbox()}onDropboxCloseButtonClick(){this.closeDropbox()}onOptionsMouseOver(e){const t=e.target.closest(".vscomp-option");t&&this.isOpened()&&(this.shouldSkipOptionInNavigation(t)?this.removeOptionFocus():this.focusOption({$option:t}))}onOptionsTouchMove(){this.removeOptionFocus()}onSearch(e){e.stopPropagation(),this.setSearchValue(e.target.value,!0)}preventPropagation(e){e.stopPropagation()}onSearchClear(e){e.stopPropagation(),"Enter"!==e.code&&"Space"!==e.code&&"click"!==e.type||(this.setSearchValue(""),this.focusSearchInput())}onToggleAllOptions(){this.toggleAllOptions()}onDropboxContainerTopOrBottomFocus(){this.closeDropbox()}onResize(){this.setOptionsContainerHeight(!0)}static observeDomChanges(){l.domObserver||(l.domObserver=new MutationObserver(e=>{e.forEach(e=>{e.removedNodes.forEach(e=>{if(e.nodeType!==Node.ELEMENT_NODE)return;const t=e.classList.contains("vscomp-ele")?[e]:[];e.querySelectorAll(".vscomp-ele").forEach(e=>t.push(e)),t.forEach(e=>{!e.isConnected&&e.virtualSelect&&e.virtualSelect.destroy()})})})}),l.domObserver.observe(document.documentElement,{childList:!0,subtree:!0}))}static disconnectDomObserver(){l.domObserver&&(l.domObserver.disconnect(),l.domObserver=null)}static addGlobalListeners(){l.hasGlobalListeners||(document.addEventListener("reset",l.onFormReset),document.addEventListener("submit",l.onFormSubmit),window.addEventListener("resize",l.onResizeThrottled),l.hasGlobalListeners=!0)}static removeGlobalListeners(){l.hasGlobalListeners&&(document.removeEventListener("reset",l.onFormReset),document.removeEventListener("submit",l.onFormSubmit),window.removeEventListener("resize",l.onResizeThrottled),l.onResizeThrottled&&"function"==typeof l.onResizeThrottled.cancel&&l.onResizeThrottled.cancel(),l.hasGlobalListeners=!1)}static registerInstance(e){l.activeInstances.add(e),l.addGlobalListeners(),l.observeDomChanges()}static unregisterInstance(e){l.activeInstances.delete(e),0===l.activeInstances.size&&(l.removeGlobalListeners(),l.disconnectDomObserver())}beforeValueSet(e){this.toggleAllOptionsClass(!e&&void 0)}beforeSelectNewValue(e){const t=this.getNewOption();if(t){const e=t.index;this.newValues.push(t.value),this.setOptionProp(e,"isCurrentNew",!1),this.setOptionProp(e,"isNew",!0)}else e&&(this.setNewOption(e),this.toggleSelectedProp(this.lastOptionIndex,!0));this.setManagedTimeout(()=>{this.setSearchValue(""),this.focusSearchInput()},0)}afterRenderWrapper(){s.addClass(this.$ele,"vscomp-ele"),this.renderSearch(),this.setEleStyles(),this.setDropboxStyles(),this.setVisibleOptionsCount(),this.setOptionsContainerHeight(),this.addEvents();try{this.setEleProps(),this.keepAlwaysOpen||this.showAsPopup||this.initDropboxPopover(),this.initialSelectedValue?this.setValueMethod(this.initialSelectedValue,this.silentInitialValueSet):this.autoSelectFirstOption&&this.visibleOptions.length&&this.setValueMethod(this.visibleOptions[0].value,this.silentInitialValueSet),this.showOptionsOnlyOnSearch&&this.setSearchValue("",!1,!0),this.initialDisabled&&this.disable(),this.autofocus&&this.focus()}catch(e){throw this.destroy(),e}}afterRenderOptions(){const e=this.getVisibleOptions(),t=!this.options.length&&!this.hasServerSearch,i=!t&&!e.length;(!this.allowNewOption||this.hasServerSearch||this.showOptionsOnlyOnSearch)&&(s.toggleClass(this.$allWrappers,"has-no-search-results",i),i?(s.setAttr(this.$noSearchResults,"tabindex","0"),s.setAttr(this.$noSearchResults,"aria-hidden","false")):(s.setAttr(this.$noSearchResults,"tabindex","-1"),s.setAttr(this.$noSearchResults,"aria-hidden","true"))),s.toggleClass(this.$allWrappers,"has-no-options",t),t?(s.setAttr(this.$noOptions,"tabindex","0"),s.setAttr(this.$noOptions,"aria-hidden","false")):(s.setAttr(this.$noOptions,"tabindex","-1"),s.setAttr(this.$noOptions,"aria-hidden","true")),this.setOptionAttr(),this.setOptionsPosition(),this.setOptionsTooltip(),document.activeElement!==this.$searchInput&&this.setManagedTimeout(()=>{const e=s.getElementsBySelector(".focused",this.$dropboxContainer)[0];void 0!==e&&e.focus({preventScroll:!0})},20)}afterSetOptionsContainerHeight(e){e&&this.showAsPopup&&this.setVisibleOptions()}afterSetSearchValue(){this.hasServerSearch?(clearTimeout(this.serverSearchTimeout),this.serverSearchTimeout=setTimeout(()=>{this.serverSearch()},this.searchDelay)):this.setVisibleOptionsCount(),this.selectAllOnlyVisible&&this.toggleAllOptionsClass(),this.focusOption({focusFirst:!0})}afterSetVisibleOptionsCount(){this.scrollToTop(),this.setOptionsHeight(),this.setVisibleOptions(),this.updatePosition()}afterValueSet(){this.scrollToTop(),this.setSearchValue(""),this.renderOptions()}afterSetOptions(e){e&&this.setSelectedProp(),this.setOptionsHeight(),this.setVisibleOptions(),this.showOptionsOnlyOnSearch&&this.setSearchValue("",!1,!0),e||this.reset()}setProps(e){const s=this.setDefaultProps(e);this.setPropsFromElementAttr(s);const{convertToBoolean:i}=t;this.$ele=s.ele,this.dropboxWrapper=s.dropboxWrapper,this.valueKey=s.valueKey,this.labelKey=s.labelKey,this.descriptionKey=s.descriptionKey,this.aliasKey=s.aliasKey,this.optionHeightText=s.optionHeight,this.optionHeight=parseFloat(this.optionHeightText),this.multiple=i(s.multiple),this.hasSearch=i(s.search),this.searchByStartsWith=i(s.searchByStartsWith),this.searchGroup=i(s.searchGroup),this.hideClearButton=i(s.hideClearButton),this.autoSelectFirstOption=i(s.autoSelectFirstOption),this.hasOptionDescription=i(s.hasOptionDescription),this.silentInitialValueSet=i(s.silentInitialValueSet),this.allowNewOption=i(s.allowNewOption),this.markSearchResults=i(s.markSearchResults),this.showSelectedOptionsFirst=i(s.showSelectedOptionsFirst),this.disableSelectAll=i(s.disableSelectAll),this.keepAlwaysOpen=i(s.keepAlwaysOpen),this.showDropboxAsPopup=i(s.showDropboxAsPopup),this.hideValueTooltipOnSelectAll=i(s.hideValueTooltipOnSelectAll),this.showOptionsOnlyOnSearch=i(s.showOptionsOnlyOnSearch),this.selectAllOnlyVisible=i(s.selectAllOnlyVisible),this.alwaysShowSelectedOptionsCount=i(s.alwaysShowSelectedOptionsCount),this.alwaysShowSelectedOptionsLabel=i(s.alwaysShowSelectedOptionsLabel),this.disableAllOptionsSelectedText=i(s.disableAllOptionsSelectedText),this.showValueAsTags=i(s.showValueAsTags),this.disableOptionGroupCheckbox=i(s.disableOptionGroupCheckbox),this.enableSecureText=i(s.enableSecureText),this.showSecureTextWarning=i(s.showSecureTextWarning,!0),this.setValueAsArray=i(s.setValueAsArray),this.disableValidation=i(s.disableValidation),this.initialDisabled=i(s.disabled),this.required=i(s.required),this.autofocus=i(s.autofocus),this.useGroupValue=i(s.useGroupValue),this.focusSelectedOptionOnOpen=i(s.focusSelectedOptionOnOpen),this.noOptionsText=s.noOptionsText,this.noSearchResultsText=s.noSearchResultsText,this.selectAllText=s.selectAllText,this.searchNormalize=s.searchNormalize,this.searchPlaceholderText=s.searchPlaceholderText,this.searchFormLabel=s.searchFormLabel,this.optionsSelectedText=s.optionsSelectedText,this.optionSelectedText=s.optionSelectedText,this.allOptionsSelectedText=s.allOptionsSelectedText,this.clearButtonText=s.clearButtonText,this.moreText=s.moreText,this.placeholder=s.placeholder,this.position=s.position,this.textDirection=s.textDirection,this.dropboxWidth=s.dropboxWidth,this.tooltipFontSize=s.tooltipFontSize,this.tooltipAlignment=s.tooltipAlignment,this.tooltipMaxWidth=s.tooltipMaxWidth,this.updatePositionThrottle=s.updatePositionThrottle,this.noOfDisplayValues=parseInt(s.noOfDisplayValues),this.zIndex=parseInt(s.zIndex),this.maxValues=parseInt(s.maxValues),this.minValues=parseInt(s.minValues),this.name=this.secureText(s.name),this.additionalClasses=s.additionalClasses,this.additionalDropboxClasses=s.additionalDropboxClasses,this.additionalDropboxContainerClasses=s.additionalDropboxContainerClasses,this.additionalToggleButtonClasses=s.additionalToggleButtonClasses,this.popupDropboxBreakpoint=s.popupDropboxBreakpoint,this.popupPosition=s.popupPosition,this.onServerSearch=s.onServerSearch,this.labelRenderer=s.labelRenderer,this.selectedLabelRenderer=s.selectedLabelRenderer,this.initialSelectedValue=0===s.selectedValue?"0":s.selectedValue,this.emptyValue=s.emptyValue,this.ariaLabelText=s.ariaLabelText,this.ariaLabelledby=s.ariaLabelledby,this.ariaLabelClearButtonText=s.ariaLabelClearButtonText,this.ariaLabelTagClearButtonText=s.ariaLabelTagClearButtonText,this.ariaLabelSearchClearButtonText=s.ariaLabelSearchClearButtonText,this.maxWidth=s.maxWidth,this.searchDelay=s.searchDelay,this.showDuration=parseInt(s.showDuration),this.hideDuration=parseInt(s.hideDuration),this.selectedValues=[],this.selectedOptions=[],this.newValues=[],this.events={},this.tooltipEnterDelay=200,this.searchValue="",this.searchValueOriginal="",this.isAllSelected=!1,(void 0===s.search&&this.multiple||this.allowNewOption||this.showOptionsOnlyOnSearch)&&(this.hasSearch=!0),this.hasServerSearch="function"==typeof this.onServerSearch,(this.maxValues||this.hasServerSearch||this.showOptionsOnlyOnSearch)&&(this.disableSelectAll=!0,this.disableOptionGroupCheckbox=!0),this.keepAlwaysOpen&&(this.dropboxWrapper="self"),this.showAsPopup=this.showDropboxAsPopup&&!this.keepAlwaysOpen&&window.innerWidth<=parseFloat(this.popupDropboxBreakpoint),this.hasSearchContainer=this.hasSearch||this.multiple&&!this.disableSelectAll,this.optionsCount=this.getOptionsCount(s.optionsCount),this.halfOptionsCount=Math.ceil(this.optionsCount/2),this.optionsHeight=this.getOptionsHeight(),this.uniqueId=this.getUniqueId(),this.shouldFocusWrapperOnClose=!0,this.ariaSetSize=0}setDefaultProps(e){const t={dropboxWrapper:"self",valueKey:"value",labelKey:"label",descriptionKey:"description",aliasKey:"alias",ariaLabelText:"Options list",ariaLabelClearButtonText:"Clear button",ariaLabelTagClearButtonText:"Remove option",ariaLabelSearchClearButtonText:"Clear search input",optionsCount:5,noOfDisplayValues:50,optionHeight:"40px",noOptionsText:"No options found",noSearchResultsText:"No results found",selectAllText:"Select All",searchNormalize:!1,searchPlaceholderText:"Search...",searchFormLabel:"Search",clearButtonText:"Clear",moreText:"more...",optionsSelectedText:"options selected",optionSelectedText:"option selected",allOptionsSelectedText:"All",placeholder:"Select",position:"bottom left",zIndex:e.keepAlwaysOpen?1:2,tooltipFontSize:"14px",tooltipAlignment:"center",tooltipMaxWidth:"300px",updatePositionThrottle:100,name:"",additionalClasses:"",additionalDropboxClasses:"",additionalDropboxContainerClasses:"",additionalToggleButtonClasses:"",maxValues:0,showDropboxAsPopup:!0,showSecureTextWarning:!0,popupDropboxBreakpoint:"576px",popupPosition:"center",hideValueTooltipOnSelectAll:!0,emptyValue:"",searchDelay:300,focusSelectedOptionOnOpen:!0,showDuration:300,hideDuration:200};return e.hasOptionDescription&&(t.optionsCount=4,t.optionHeight="50px"),Object.assign(t,e)}setPropsFromElementAttr(e){const t=e.ele;Object.keys(r).forEach(s=>{let i=t.getAttribute(s);-1===o.indexOf(s)||""!==i&&"true"!==i||(i=!0),i&&(e[r[s]]=i)})}setEleProps(){const{$ele:e}=this;e.virtualSelect=this,e.value=this.multiple?[]:"",e.name=this.name,e.disabled=!1,e.required=this.required,e.autofocus=this.autofocus,e.multiple=this.multiple,e.form=e.closest("form"),e.reset=l.reset,e.setValue=l.setValueMethod,e.setOptions=l.setOptionsMethod,e.setDisabledOptions=l.setDisabledOptionsMethod,e.setEnabledOptions=l.setEnabledOptionsMethod,e.toggleSelectAll=l.toggleSelectAll,e.isAllSelected=l.isAllSelected,e.addOption=l.addOptionMethod,e.getNewValue=l.getNewValueMethod,e.getDisplayValue=l.getDisplayValueMethod,e.getSelectedOptions=l.getSelectedOptionsMethod,e.getDisabledOptions=l.getDisabledOptionsMethod,e.open=l.openMethod,e.close=l.closeMethod,e.focus=l.focusMethod,e.enable=l.enableMethod,e.disable=l.disableMethod,e.destroy=l.destroyMethod,e.validate=l.validateMethod,e.toggleRequired=l.toggleRequiredMethod,this.hasDropboxWrapper&&(this.$dropboxWrapper.virtualSelect=this)}setValueMethod(e,s){const i={},o={};let n=[];const r=this.multiple;let a=t.normalizeValues(e);if(a){if(Array.isArray(a)||(a=[a]),r){const{maxValues:e}=this;e&&a.length>e&&a.splice(e)}else a.length>1&&(a=[a[0]]);this.useGroupValue&&(a=this.setGroupOptionsValue(a)),a.forEach((e,t)=>{i[e]=!0,o[e]=t}),this.allowNewOption&&a&&this.setNewOptionsFromValue(a)}this.options.forEach(e=>{const s=t.normalizeValues(e.value);!0!==i[s]||e.isDisabled||e.isGroupTitle?e.isSelected=!1:(e.isSelected=!0,n.push(e.value))}),r?(this.hasOptionGroup&&this.setGroupsSelectedProp(),n.sort((e,s)=>o[t.normalizeValues(e)]-o[t.normalizeValues(s)])):[n]=n,this.beforeValueSet(),this.setValue(n,{disableEvent:s}),this.afterValueSet()}setGroupOptionsValue(e){const t=[],s={},i={};return e.forEach(e=>{i[e]=!0}),this.options.forEach(e=>{const{value:o}=e,n=!0===i[o];e.isGroupTitle?n&&(s[e.index]=!0):(n||s[e.groupIndex])&&t.push(o)}),t}setGroupsSelectedProp(){const e=this.isAllGroupOptionsSelected.bind(this);this.options.forEach(t=>{t.isGroupTitle&&(t.isSelected=e(t.index))})}setOptionsMethod(e,t){this.setOptions(e),this.afterSetOptions(t)}setDisabledOptionsMethod(e,t=!1){this.setDisabledOptions(e,!0),t||(this.setValueMethod(null),this.toggleAllOptionsClass()),this.setVisibleOptions()}setDisabledOptions(e,t=!1){let s=[];if(e)if(!0===e)t&&this.options.forEach(e=>(e.isDisabled=!0,s.push(e.value),e));else{s=e.map(e=>e.toString());const i={};s.forEach(e=>{i[e]=!0}),t&&this.options.forEach(e=>(e.isDisabled=!0===i[e.value],e))}else t&&this.options.forEach(e=>(e.isDisabled=!1,e));this.disabledOptions=s}setEnabledOptionsMethod(e,t=!1){this.setEnabledOptions(e),t||(this.setValueMethod(null),this.toggleAllOptionsClass()),this.setVisibleOptions()}setEnabledOptions(e){if(void 0===e)return;const t=[];if(!0===e)this.options.forEach(e=>(e.isDisabled=!1,e));else{const s={};e.forEach(e=>{s[e]=!0}),this.options.forEach(e=>{const i=!0!==s[e.value];return e.isDisabled=i,i&&t.push(e.value),e})}this.disabledOptions=t}setOptions(e=[]){const s=[],i=this.disabledOptions.length,{valueKey:o,labelKey:n,descriptionKey:r,aliasKey:a,hasOptionDescription:l}=this,{getString:h,convertToBoolean:p}=t,c=this.secureText.bind(this),u=this.getAlias.bind(this);let d=0,v=!1;const b={};let m=!1;this.disabledOptions.forEach(e=>{b[e]=!0});const f=e=>{"object"!=typeof e&&(e={[o]:e,[n]:e});const g=c(h(e[o])),S=c(h(e[n])),O=e.options,x=!!O,y={index:d,value:g,valueNormalized:g.toLowerCase(),label:S,labelNormalized:this.searchNormalize&&""!==S.trim()?t.normalizeString(S).toLowerCase():S.toLowerCase(),alias:u(e[a]),isVisible:p(e.isVisible,!0),isNew:e.isNew||!1,isGroupTitle:x,classNames:e.classNames};if(m||""!==g||(m=!0),i&&(y.isDisabled=!0===b[g]),e.isGroupOption&&(y.isGroupOption=!0,y.groupIndex=e.groupIndex),l){const s=c(h(e[r]));y.description=s,y.descriptionNormalized=this.searchNormalize&&""!==s.trim()?t.normalizeString(s).toLowerCase():s.toLowerCase()}if(e.customData&&(y.customData=e.customData),s.push(y),d+=1,x){const e=y.index;v=!0,O.forEach(t=>{t.isGroupOption=!0,t.groupIndex=e,f(t)})}};Array.isArray(e)&&e.forEach(f);const g=s.length,{$ele:S}=this;S.options=s,S.length=g,this.options=s,this.visibleOptionsCount=g,this.lastOptionIndex=g-1,this.newValues=[],this.hasOptionGroup=v,this.hasEmptyValueOption=m,this.setSortedOptions()}setServerOptions(e=[]){this.setOptionsMethod(e,!0);const{selectedOptions:t}=this,i=this.options;let o=!1;if(t.length){const e={};o=!0,i.forEach(t=>{e[t.value]=!0}),t.forEach(t=>{!0!==e[t.value]&&(t.isVisible=!1,i.push(t))}),this.setOptionsMethod(i,!0)}this.allowNewOption&&this.searchValue&&(i.some(e=>e.label.toLowerCase()===this.searchValue)||(o=!0,this.setNewOption())),o?(this.setVisibleOptionsCount(),this.multiple&&this.toggleAllOptionsClass(),this.setValueText()):this.updatePosition(),this.setVisibleOptionsCount(),s.removeClass(this.$allWrappers,"server-searching")}setSelectedOptions(){this.selectedOptions=this.options.filter(e=>e.isSelected)}setSortedOptions(){let e=[...this.options];this.showSelectedOptionsFirst&&this.selectedValues.length&&(e=this.hasOptionGroup?this.sortOptionsGroup(e):this.sortOptions(e)),this.sortedOptions=e}setVisibleOptions(){let e=[...this.sortedOptions];const t=2*this.optionsCount,s=this.getVisibleStartIndex(),i=this.getNewOption(),o=s+t-1;let n=0;i&&(i.visibleIndex=n,n+=1),e=e.filter(e=>{let t=!1;return e.isVisible&&!e.isCurrentNew&&(t=n>=s&&n<=o,e.visibleIndex=n,n+=1),t}),i&&(e=[i,...e]),this.visibleOptions=e,this.visibleOptionsCount=e.length,this.renderOptions()}setOptionsPosition(e){const t=parseInt((e||this.getVisibleStartIndex())*this.optionHeight);this.$options.style.transform=`translate3d(0, ${t}px, 0)`,s.setData(this.$options,"top",t)}setOptionsTooltip(){const e=this.getVisibleOptions(),{hasOptionDescription:t}=this;e.forEach(e=>{const i=this.$dropboxContainer.querySelector(`.vscomp-option[data-index="${e.index}"]`);s.setData(i.querySelector(".vscomp-option-text"),"tooltip",e.label),t&&s.setData(i.querySelector(".vscomp-option-description"),"tooltip",e.description)})}setValue(e,{disableEvent:i=!1,disableValidation:o=!1}={}){const n=t.normalizeValues(e);this.hasEmptyValueOption&&""===n||n?Array.isArray(n)?this.selectedValues=[...n]:this.selectedValues=[n]:this.selectedValues=[];const r=this.getValue();this.$ele.value=r,this.$hiddenInput.value=this.getInputValue(r),this.isMaxValuesSelected=!!(this.maxValues&&this.maxValues<=this.selectedValues.length),this.toggleAllOptionsClass(),this.setValueText();const a=t.isNotEmpty(this.selectedValues);s.toggleClass(this.$allWrappers,"has-value",a),s.toggleClass(this.$allWrappers,"max-value-selected",this.isMaxValuesSelected),s.setAttr(this.$clearButton,"tabindex",a?"0":"-1"),s.setAria(this.$clearButton,"hidden",!1===a),o||this.validate(),i||s.dispatchEvent(this.$ele,"change",!0)}setValueText(){const{multiple:e,selectedValues:i,noOfDisplayValues:o,showValueAsTags:n,$valueText:r,selectedLabelRenderer:a}=this,l=[];let h=[];const p=i.length;let c=0;const u=this.isAllSelected&&!this.hasServerSearch&&!this.disableAllOptionsSelectedText&&!n;if(u&&this.hideValueTooltipOnSelectAll)r.innerHTML=`${this.allOptionsSelectedText} (${p})`;else{this.getSelectedOptions({fullDetails:!0,keepSelectionOrder:!0}).some(e=>{if(e.isCurrentNew)return!1;if(c>=o)return!0;let{label:s}=e;if("function"==typeof a&&(s=a(e)),l.push(s),c+=1,n){const i=t.willTextOverflow(r.parentElement,s)?this.getTooltipAttrText(s,!1,!0):"";let o="";this.ariaLabelTagClearButtonText&&(o=`aria-label="${s.replace(/<[^>]+>/gi,"").trim()}, ${this.ariaLabelTagClearButtonText}"`);const n=`\n ${s}\n \n \n \n `;h.push(n)}else h.push(s);return!1});const i=p-o;i>0&&h.push(`+ ${i} ${this.moreText}`);const d=l.join(", ");if(""===d)r.innerHTML=this.placeholder;else if(r.innerHTML=d,e){const{maxValues:e}=this;if(this.alwaysShowSelectedOptionsCount||s.hasEllipsis(r)||e||n){let t=`${p}`;if(e&&(t+=` / ${e}`),u)r.innerHTML=`${this.allOptionsSelectedText} (${p})`;else if(n)r.innerHTML=h.join(""),this.$valueTags=r.querySelectorAll(".vscomp-value-tag"),this.setValueTagAttr();else if(!this.alwaysShowSelectedOptionsLabel){const e=1===p?this.optionSelectedText:this.optionsSelectedText;r.innerHTML=`${t} ${e}`}}else h=[]}}let d="";0===p?d=this.placeholder:n||(d=h.join(", ")),n||s.setData(r,"tooltip",d),e&&(n?this.updatePosition():s.setData(r,"tooltipEllipsisOnly",0===p))}setSearchValue(e,t=!1,i=!1){if(e===this.searchValueOriginal&&!i)return;t||(this.$searchInput.value=e);const o=e.replace(/\\/g,"").toLowerCase().trim();this.searchValue=o,this.searchValueOriginal=e,s.toggleClass(this.$allWrappers,"has-search-value",e),s.setAttr(this.$searchClear,"tabindex",""!==e?"0":"-1"),s.setAria(this.$searchClear,"hidden",""===e),this.afterSetSearchValue()}setVisibleOptionsCount(){let e,s=0,i=!1;const{searchGroup:o,showOptionsOnlyOnSearch:n,searchByStartsWith:r}=this;let{searchValue:a}=this;a=this.searchNormalize&&""!==a.trim()?t.normalizeString(a):a;const l=this.isOptionVisible.bind(this);this.hasOptionGroup&&(e=this.getVisibleOptionGroupsMapping(a)),this.options.forEach(t=>{if(t.isCurrentNew)return;let h;n&&!a?(t.isVisible=!1,h={isVisible:!1,hasExactOption:!1}):h=l({data:t,searchValue:a,hasExactOption:i,visibleOptionGroupsMapping:e,searchGroup:o,searchByStartsWith:r}),h.isVisible&&(s+=1),i||(i=h.hasExactOption)}),this.allowNewOption&&(a&&!i?(this.setNewOption(),s+=1):this.removeNewOption()),this.visibleOptionsCount=s,this.afterSetVisibleOptionsCount()}calculateAriaMetadata(){let e=0,t=0;if((this.sortedOptions&&this.sortedOptions.length?this.sortedOptions:this.options).forEach(s=>{if(s.isCurrentNew)s.filteredIndex=void 0;else if(!0===s.isVisible){const i=s.isGroupTitle&&this.multiple&&!this.disableOptionGroupCheckbox;!s.isGroupTitle||i?(t+=1,e+=1,s.filteredIndex=t):s.filteredIndex=void 0}else s.filteredIndex=void 0}),this.allowNewOption){const s=this.getNewOption();s&&!0===s.isVisible?(t+=1,e+=1,s.filteredIndex=t):s&&(s.filteredIndex=void 0)}this.ariaSetSize=e}setOptionProp(e,t,s){this.options[e]&&(this.options[e][t]=s)}setOptionsHeight(){this.$optionsList.style.height=this.optionHeight*this.visibleOptionsCount+"px"}setOptionsContainerHeight(e){let t;e?this.showAsPopup&&(this.optionsCount=this.getOptionsCount(),this.halfOptionsCount=Math.ceil(this.optionsCount/2),t=this.getOptionsHeight(),this.optionsHeight=t):(t=this.optionsHeight,this.keepAlwaysOpen&&(s.setStyle(this.$noOptions,"height",t),s.setStyle(this.$noSearchResults,"height",t))),s.setStyle(this.$optionsContainer,"max-height",t),this.afterSetOptionsContainerHeight(e)}setNewOption(e){const t=e||this.searchValueOriginal.trim();if(!t)return;const s=this.getNewOption();if(s){const e=s.index;this.setOptionProp(e,"value",this.secureText(t)),this.setOptionProp(e,"label",this.secureText(t))}else{const s={value:t,label:t};e?(s.isNew=!0,this.newValues.push(t)):s.isCurrentNew=!0,this.addOption(s)}}setSelectedProp(){const e={};this.selectedValues.forEach(t=>{e[t]=!0}),this.options.forEach(t=>{!0===e[t.value]&&(t.isSelected=!0)})}setNewOptionsFromValue(e){if(!e)return;const t=this.setNewOption.bind(this),s={};this.options.forEach(e=>{s[e.value]=!0}),e.forEach(e=>{e&&!0!==s[e]&&t(e)})}setDropboxWrapperWidth(){if(this.showAsPopup)return;const e=this.dropboxWidth||`${this.$wrapper.offsetWidth}px`;s.setStyle(this.$dropboxContainer,"max-width",e)}setEleStyles(){const{maxWidth:e}=this,t={};e&&(t["max-width"]=e),s.setStyles(this.$ele,t)}setDropboxStyles(){const{dropboxWidth:e}=this,t={},i={"z-index":this.zIndex};e&&(this.showAsPopup?t["max-width"]=e:i.width=e),s.setStyles(this.$dropboxContainer,i),s.setStyles(this.$dropbox,t)}setOptionAttr(){const{$visibleOptions:e}=this,{options:t}=this,i=`${this.optionHeight}px`,{setStyle:o,getData:n,setData:r}=s;e&&e.length&&e.forEach(e=>{const s=t[n(e,"index")];o(e,"height",i),r(e,"value",s.value)})}setValueTagAttr(){const{$valueTags:e}=this;if(!e||!e.length)return;const{getData:t,setData:i}=s,{options:o}=this;e.forEach(e=>{const s=t(e,"index");if(void 0!==s){const t=o[s];i(e,"value",t.value)}})}setScrollTop(){const{selectedValues:e}=this;if(this.showSelectedOptionsFirst||!this.focusSelectedOptionOnOpen||0===e.length)return;const t={};let s;e.forEach(e=>{t[e]=!0}),this.options.some(e=>!!t[e.value]&&(s=e.visibleIndex,!0)),s&&(this.$optionsContainer.scrollTop=this.optionHeight*s)}getVisibleOptions(){return this.visibleOptions||[]}getValue(){let e;return e=this.multiple?this.useGroupValue?this.getGroupValue():this.selectedValues:this.selectedValues[0]||"",t.normalizeValues(e)}getGroupValue(){const e=[],t={};return this.options.forEach(s=>{if(!s.isSelected)return;const{value:i}=s;s.isGroupTitle?i&&(t[s.index]=!0,e.push(i)):!0!==t[s.groupIndex]&&e.push(i)}),e}getInputValue(e){let t=e;return t&&t.length?this.setValueAsArray&&this.multiple&&(t=JSON.stringify(t)):t=this.emptyValue,t}getFirstVisibleOptionIndex(){return Math.ceil(this.$optionsContainer.scrollTop/this.optionHeight)}getVisibleStartIndex(){let e=this.getFirstVisibleOptionIndex()-this.halfOptionsCount;return e<0&&(e=0),e}getTooltipAttrText(e,i=!1,o=!1){const n={"data-tooltip":(t.containsHTML(e)?t.replaceDoubleQuotesWithHTML(e):e)||"","data-tooltip-enter-delay":this.tooltipEnterDelay,"data-tooltip-z-index":this.zIndex,"data-tooltip-font-size":this.tooltipFontSize,"data-tooltip-alignment":this.tooltipAlignment,"data-tooltip-max-width":this.tooltipMaxWidth,"data-tooltip-ellipsis-only":i,"data-tooltip-allow-html":o};return s.getAttributesText(n)}getOptionObj(e){if(!e)return;const{getString:s}=t,i=this.secureText.bind(this),o=i(s(e.value)),n=i(s(e.label)),r=i(s(e.description));return{index:e.index,value:o,valueNormalized:o.toLowerCase(),label:n,labelNormalized:this.searchNormalize&&""!==n.trim()?t.normalizeString(n).toLowerCase():n.toLowerCase(),description:r,descriptionNormalized:this.searchNormalize&&""!==r.trim()?t.normalizeString(r).toLowerCase():r.toLowerCase(),alias:this.getAlias(e.alias),isCurrentNew:e.isCurrentNew||!1,isNew:e.isNew||!1,isVisible:!0}}getNewOption(){const e=this.options[this.lastOptionIndex];if(e&&e.isCurrentNew)return e}getOptionIndex(e){let t;return this.options.some(s=>s.value===e&&(t=s.index,!0)),t}getNewValue(){const e={};this.newValues.forEach(t=>{e[t]=!0});const t=this.selectedValues.filter(t=>!0===e[t]);return this.multiple?t:t[0]}getAlias(e){let t=e;return t&&(t=Array.isArray(t)?t.join(","):t.toString().trim(),t=t.toLowerCase()),t||""}getDisplayValue(){const e=[];return this.options.forEach(t=>{t.isSelected&&e.push(t.label)}),this.multiple?e:e[0]||""}getSelectedOptions({fullDetails:e=!1,keepSelectionOrder:t=!1}={}){const{valueKey:s,labelKey:i,selectedValues:o}=this,n=[];if(this.options.forEach(t=>{if(t.isSelected&&!t.isGroupTitle)if(e)n.push(t);else{const e={[s]:t.value,[i]:t.label};t.isNew&&(e.isNew=!0),t.customData&&(e.customData=t.customData),n.push(e)}}),t){const e={};o.forEach((t,s)=>{e[t]=s}),n.sort((t,s)=>e[t.value]-e[s.value])}return this.multiple||e?n:n[0]}getDisabledOptions(){const{valueKey:e,labelKey:t,disabledOptions:s}=this,i={},o=[];return s.forEach(e=>{i[e]=!0}),this.options.forEach(({value:s,label:n})=>{i[s]&&o.push({[e]:s,[t]:n})}),o}getVisibleOptionGroupsMapping(e){let{options:t}=this;const s={},i=this.isOptionVisible.bind(this);return t=this.structureOptionGroup(t),t.forEach(t=>{s[t.index]=t.options.some(t=>i({data:t,searchValue:e}).isVisible)}),s}getOptionsCount(e){let t;if(this.showAsPopup){let e=80*window.innerHeight/100-48;this.hasSearchContainer&&(e-=40),t=Math.floor(e/this.optionHeight)}else t=parseInt(e);return t}getOptionsHeight(){return this.optionsCount*this.optionHeight+"px"}isSelectableGroupTitle(e){return e&&s.hasClass(e,"group-title")&&this.multiple&&!this.disableOptionGroupCheckbox}shouldSkipOptionInNavigation(e){return!!e&&(!!s.hasClass(e,"disabled")||s.hasClass(e,"group-title")&&!this.isSelectableGroupTitle(e))}getSibling(e,t){const s="next"===t?"nextElementSibling":"previousElementSibling";let i=e;do{i&&(i=i[s])}while(this.shouldSkipOptionInNavigation(i));return i}getUniqueId(){const e=t.getRandomInt(1e4);return document.querySelector(`#vscomp-ele-wrapper-${e}`)?this.getUniqueId():e}initDropboxPopover(){const e={ele:this.$ele,target:this.$dropboxContainer,position:this.position,zIndex:this.zIndex,margin:4,transitionDistance:30,hideArrowIcon:!0,disableManualAction:!0,disableUpdatePosition:!this.hasDropboxWrapper,updatePositionThrottle:this.updatePositionThrottle,showDuration:this.showDuration,hideDuration:this.hideDuration,afterShow:this.afterShowPopper.bind(this),afterHide:this.afterHidePopper.bind(this)};this.dropboxPopover=new PopoverComponent(e)}openDropbox(e){l.lastInteractedInstance=this;let t="";e||(t=this.$dropboxContainer.style.transition,this.$dropboxContainer.style.transition="none"),this.isSilentOpen=e,l.openInstances.forEach(e=>{if(e!==this){const t=e;t.shouldFocusWrapperOnClose=!1,t.closeDropbox(!0)}}),l.openInstances.add(this),s.setAttr(this.$dropboxWrapper,"tabindex","0"),s.setAria(this.$dropboxWrapper,"hidden",!1),s.setAttr(this.$dropboxContainerTop,"tabindex","0"),s.setAria(this.$dropboxContainerTop,"hidden",!1),s.setAttr(this.$dropboxContainerBottom,"tabindex","0"),s.setAria(this.$dropboxContainerBottom,"hidden",!1),e?s.setStyle(this.$dropboxContainer,"display","inline-flex"):(s.dispatchEvent(this.$ele,"beforeOpen"),s.setAria(this.$wrapper,"expanded",!0)),this.setDropboxWrapperWidth(),s.removeClass(this.$allWrappers,"closed"),s.changeTabIndex(this.$allWrappers,0),e||(this.$dropboxContainer.offsetHeight,this.$dropboxContainer.style.transition=t),this.dropboxPopover&&!e?this.dropboxPopover.show():this.afterShowPopper()}afterShowPopper(){const e=this.isSilentOpen;this.isSilentOpen=!1,e||(this.moveSelectedOptionsFirst(),this.setScrollTop(),s.addClass(this.$allWrappers,"focused"),this.showAsPopup?(s.addClass(this.$body,"vscomp-popup-active"),this.isPopupActive=!0):this.focusElementOnOpen(),s.dispatchEvent(this.$ele,"afterOpen"))}closeDropbox(e){if(this.isSilentClose=e,l.openInstances.delete(this),!1===this.isOpened())return;if(this.keepAlwaysOpen)return void this.removeOptionFocus();const t=document.activeElement,i=t&&this.$wrapper.contains(t)||this.hasDropboxWrapper&&t&&this.$dropboxWrapper.contains(t);this.shouldFocusWrapperOnClose&&l.lastInteractedInstance===this&&!e&&(null===t||t===document.body||i)&&this.$wrapper.focus(),e?s.setStyle(this.$dropboxContainer,"display",""):(s.dispatchEvent(this.$ele,"beforeClose"),s.setAria(this.$wrapper,"expanded",!1),s.setAria(this.$wrapper,"activedescendant",""),s.setAria(this.$dropboxContainer,"activedescendant","")),this.dropboxPopover&&!e?(this.dropboxPopover.hide(),s.setAttr(this.$dropboxWrapper,"tabindex","-1"),s.setAria(this.$dropboxWrapper,"hidden",!0),s.setAttr(this.$dropboxContainerTop,"tabindex","-1"),s.setAria(this.$dropboxContainerTop,"hidden",!0),s.setAttr(this.$dropboxContainerBottom,"tabindex","-1"),s.setAria(this.$dropboxContainerBottom,"hidden",!0)):this.afterHidePopper(),this.setSearchValue("")}afterHidePopper(){const e=this.isSilentClose;this.isSilentClose=!1,s.removeClass(this.$allWrappers,"focused"),this.removeOptionFocus(),!e&&this.isPopupActive&&(s.removeClass(this.$body,"vscomp-popup-active"),this.isPopupActive=!1),s.addClass(this.$allWrappers,"closed"),e||s.dispatchEvent(this.$ele,"afterClose"),this.shouldFocusWrapperOnClose=!0,s.setAttr(this.$dropboxWrapper,"tabindex","-1"),s.setAria(this.$dropboxWrapper,"hidden",!0),s.setAttr(this.$dropboxContainerTop,"tabindex","-1"),s.setAria(this.$dropboxContainerTop,"hidden",!0),s.setAttr(this.$dropboxContainerBottom,"tabindex","-1"),s.setAria(this.$dropboxContainerBottom,"hidden",!0)}moveSelectedOptionsFirst(){this.$optionsContainer.scrollTop&&this.selectedValues.length||this.setVisibleOptions(),this.showSelectedOptionsFirst&&(this.setSortedOptions(),this.scrollToTop(),this.setVisibleOptions())}toggleDropbox(){l.lastInteractedInstance=this,this.isOpened()?this.closeDropbox():this.openDropbox()}updatePosition(){this.dropboxPopover&&this.isOpened()&&this.$ele.updatePosition()}isOpened(){return!s.hasClass(this.$wrapper,"closed")}focusSearchInput(){const e=this.$searchInput;e&&e.focus()}focusElementOnOpen(){const e=this.$searchInput,t=!this.options.length&&!this.hasServerSearch;if(e)t&&!this.allowNewOption?(s.setAttr(e,"disabled",""),this.$noOptions.focus()):(e.removeAttribute("disabled"),e.focus());else{const e=this.$dropbox.querySelector('[tabindex="0"]');void 0!==s.getData(e,"index")?this.focusOption({direction:"next"}):e?e.focus():this.focusFirstVisibleOption()}}focusFirstVisibleOption(){let e=this.$optionsContainer.querySelector(`[data-index='${this.getFirstVisibleOptionIndex()}']`);e?(this.shouldSkipOptionInNavigation(e)&&(e=this.getSibling(e,"next")),e&&(s.setAttr(e,"tabindex","0"),this.$optionsContainer.scrollTop=this.optionHeight*this.getFirstVisibleOptionIndex(),this.focusOption({focusFirst:!0}),e.focus())):(e=this.$dropbox.querySelector('[tabindex="0"]'),e&&e.focus())}focusOption({direction:e,$option:t,focusFirst:i}={}){const o=this.$dropboxContainer.querySelector(".vscomp-option.focused");let n;if(t)n=t;else if(!o||i){const e=this.getFirstVisibleOptionIndex();n=this.$dropboxContainer.querySelector(`.vscomp-option[data-visible-index="${e}"]`),this.shouldSkipOptionInNavigation(n)&&(n=this.getSibling(n,"next"))}else n=this.getSibling(o,e);n&&n!==o&&(o&&this.toggleOptionFocusedState(o,!1),this.toggleOptionFocusedState(n,!0),this.toggleFocusedProp(s.getData(n,"index"),!0),this.moveFocusedOptionToView(n))}moveFocusedOptionToView(e){const t=e||this.$dropboxContainer.querySelector(".vscomp-option.focused");if(!t)return;let i;const o=this.$optionsContainer.getBoundingClientRect(),n=t.getBoundingClientRect(),r=o.top,a=o.bottom,l=o.height,h=n.top,p=n.bottom,c=n.height,u=t.offsetTop,d=s.getData(this.$options,"top","number");r>h?i=u+d:a{if(e.isDisabled||e.isGroupTitle||!e.isVisible||e.isSelected)return;const{index:t}=e;if(t>o&&t{e(parseInt(t))})}this.setManagedTimeout(()=>{this.renderOptions()},0)}toggleAllOptions(e){if(!this.multiple||this.disableSelectAll)return;const t="boolean"==typeof isSelected?e:!s.hasClass(this.$toggleAllCheckbox,"checked"),i=[],{selectAllOnlyVisible:o}=this;this.options.forEach(e=>{const s=e;if(s.isDisabled||s.isCurrentNew)return;const{isVisible:n,isSelected:r}=s;!t&&(!o||n||!r)||t&&o&&!n&&!r?s.isSelected=!1:(s.isSelected=!0,s.isGroupTitle||i.push(s.value))}),this.toggleAllOptionsClass(t),this.setValue(i),this.renderOptions()}toggleAllOptionsClass(e){if(!this.multiple)return;let t=!1;"boolean"==typeof e||(e=this.isAllOptionsSelected()),!e&&this.selectAllOnlyVisible&&""!==this.searchValue&&(this.visibleOptionsCount>0||""===this.searchValue)&&(t=this.isAllOptionsSelected(!0)),s.toggleClass(this.$toggleAllCheckbox,"checked",e||t),this.isAllSelected=e}isAllOptionsSelected(e){let t=!1;return this.options.length&&this.selectedValues.length&&(t=!this.options.some(t=>!t.isSelected&&!t.isDisabled&&!t.isGroupTitle&&(!e||t.isVisible))),t}isAllGroupOptionsSelected(e){let t=!1;return this.options.length&&(t=!this.options.some(t=>!t.isSelected&&!t.isDisabled&&!t.isGroupTitle&&t.groupIndex===e)),t}toggleGroupOptionsParent(e,t){if(!this.hasOptionGroup||this.disableOptionGroupCheckbox||!e)return;let i=s.getData(e,"groupIndex");void 0!==i&&(i=parseInt(i));const o=this.$options.querySelector(`.vscomp-option[data-index="${i}"]`),n="boolean"==typeof t?t:this.isAllGroupOptionsSelected(i);this.toggleGroupTitleCheckbox(o,n),this.toggleGroupTitleProp(i,n)}toggleGroupTitleProp(e,t){const s="boolean"==typeof t?t:this.isAllGroupOptionsSelected(e);this.toggleSelectedProp(e,s)}toggleGroupOptions(e,i){if(!this.hasOptionGroup||this.disableOptionGroupCheckbox||!e)return;const o=s.getData(e,"index","number"),{selectedValues:n,selectAllOnlyVisible:r}=this,a={},{removeItemFromArray:l}=t;n.forEach(e=>{a[e]=!0}),this.options.forEach(e=>{if(e.isDisabled||e.groupIndex!==o)return;const{value:t}=e;!i||r&&!e.isVisible?(e.isSelected=!1,a[t]&&l(n,t)):(e.isSelected=!0,a[t]||n.push(t))}),this.toggleAllOptionsClass(!!i&&null),this.setValue(n),this.setManagedTimeout(()=>{this.renderOptions()},0)}toggleGroupTitleCheckbox(e,t){if(!e)return;const i=s.getData(e,"index","number");this.toggleSelectedProp(i,t),this.toggleOptionSelectedState(e,t)}toggleFocusedProp(e,t=!1){this.focusedOptionIndex&&this.setOptionProp(this.focusedOptionIndex,"isFocused",!1),this.setOptionProp(e,"isFocused",t),this.focusedOptionIndex=e}toggleSelectedProp(e,t=!1){this.setOptionProp(e,"isSelected",t)}scrollToTop(){const{scrollTop:e}=this.$optionsContainer;e>0&&(this.$optionsContainer.scrollTop=0)}reset(e=!1,t=!1){this.options.forEach(e=>{e.isSelected=!1}),this.beforeValueSet(!0),this.setValue(null,{disableEvent:t,disableValidation:e}),this.afterValueSet(),e&&s.removeClass(this.$allWrappers,"has-error"),s.dispatchEvent(this.$ele,"reset")}addOption(e,t){if(!e)return;this.lastOptionIndex+=1;const s=this.getOptionObj({...e,index:this.lastOptionIndex});this.options.push(s),this.sortedOptions.push(s),t&&(this.visibleOptionsCount+=1,this.afterSetOptions())}removeOption(e){(e||0===e)&&(this.options.splice(e,1),this.lastOptionIndex-=1)}removeNewOption(){const e=this.getNewOption();e&&this.removeOption(e.index)}sortOptions(e){return e.sort((e,t)=>{const s=e.isSelected||e.isAnySelected,i=t.isSelected||t.isAnySelected;return s||i?s&&(!i||e.index{const s=e.options;e.isAnySelected=s.some(e=>e.isSelected),e.isAnySelected&&t(s)}),t(s),this.destructureOptionGroup(s)}isOptionVisible({data:e,searchValue:s,hasExactOption:i,visibleOptionGroupsMapping:o,searchGroup:n,searchByStartsWith:r}){const a=null!=e.valueNormalized?e.valueNormalized:e.value.toLowerCase();let l=e.labelNormalized;if(null==l){const s=(e.label||"").trim();l=this.searchNormalize&&""!==s?t.normalizeString(s).toLowerCase():s.toLowerCase()}const{description:h,alias:p}=e;let{descriptionNormalized:c}=e;if(null==c){const e=h||"";c=this.searchNormalize&&""!==e.trim()?t.normalizeString(e).toLowerCase():e.toLowerCase()}let u=r?l.startsWith(s):l.includes(s);return!e.isGroupTitle||n&&u||(u=o[e.index]),r||!p||u||(u=p.includes(s)),r||!c||u||(u=c.includes(s)),e.isVisible=u,i||(i=l===s||a===s),{isVisible:u,hasExactOption:i}}structureOptionGroup(e){const t=[],s={};return e.forEach(e=>{if(e.isGroupTitle){const i=[];e.options=i,s[e.index]=i,t.push(e)}}),e.forEach(e=>{e.isGroupOption&&s[e.groupIndex].push(e)}),t}destructureOptionGroup(e){let t=[];return e.forEach(e=>{t.push(e),t=t.concat(e.options)}),t}serverSearch(){s.removeClass(this.$allWrappers,"has-no-search-results"),s.addClass(this.$allWrappers,"server-searching"),this.setSelectedOptions(),this.onServerSearch(this.searchValue,this)}removeValue(e){const{selectedValues:i}=this,o=s.getData(e,"value");t.removeItemFromArray(i,o),this.setValueMethod(i)}focus(){this.$wrapper.focus()}enable(){this.$ele.disabled=!1,this.$ele.removeAttribute("disabled"),this.$hiddenInput.removeAttribute("disabled"),s.setAria(this.$wrapper,"disabled",!1),s.changeTabIndex(this.$wrapper,0)}disable(){this.$ele.disabled=!0,this.$ele.setAttribute("disabled",""),this.$hiddenInput.setAttribute("disabled",""),s.setAria(this.$wrapper,"disabled",!0),s.changeTabIndex(this.$wrapper,-1),this.$wrapper.blur()}validate(){if(this.disableValidation)return!0;let e=!1;const{selectedValues:i,minValues:o}=this;return this.required&&(t.isEmpty(i)||this.multiple&&o&&i.length{this.managedTimeouts.delete(s),e()},t);return this.managedTimeouts.add(s),s}clearManagedTimeouts(){this.managedTimeouts&&(this.managedTimeouts.forEach(e=>clearTimeout(e)),this.managedTimeouts.clear())}destroy(){if(this.isDestroyed)return;this.isDestroyed=!0;const{$ele:e}=this;e.virtualSelect=void 0,e.value=void 0,e.innerHTML="",l.openInstances.delete(this),this===l.lastInteractedInstance&&(l.lastInteractedInstance=null),this.serverSearchTimeout&&(clearTimeout(this.serverSearchTimeout),this.serverSearchTimeout=null),this.clearManagedTimeouts(),this.removeEvents(),this.hasDropboxWrapper&&(this.$dropboxWrapper.virtualSelect=void 0,this.$dropboxWrapper.remove()),this.dropboxPopover&&this.dropboxPopover.destroy(),s.removeClass(e,"vscomp-ele"),this.events={},l.unregisterInstance(this)}createSecureTextElements(){this.$secureDiv=document.createElement("div"),this.$secureText=document.createTextNode(""),this.$secureDiv.appendChild(this.$secureText)}secureText(e){return e&&this.enableSecureText?(this.$secureText.nodeValue=t.replaceDoubleQuotesWithHTML(e),this.$secureDiv.innerHTML):e}warnIfSecureTextDisabled(){l.secureTextWarningShown||this.enableSecureText||!this.showSecureTextWarning||(l.secureTextWarningShown=!0,console.warn("[virtual-select] Option text (label, value, description) and any `customData` used in markup are rendered as HTML and are NOT escaped because `enableSecureText` is disabled (the default, kept off for performance on large datasets). If any option text can come from untrusted input, set `enableSecureText: true` to prevent XSS. Docs: https://sa-si-dev.github.io/virtual-select/#/properties"))}toggleRequired(e){this.required=t.convertToBoolean(e),this.$ele.required=this.required}toggleOptionSelectedState(e,t){let i=t;void 0===i&&(i=!s.hasClass(e,"selected")),s.toggleClass(e,"selected",i),s.setAria(e,"selected",i)}toggleOptionFocusedState(e,t){e&&(s.toggleClass(e,"focused",t),s.setAttr(e,"tabindex",t?"0":"-1"),document.activeElement!==this.$searchInput&&e.focus(),t&&(s.setAria(this.$wrapper,"activedescendant",e.id),s.setAria(this.$dropboxContainer,"activedescendant",e.id)))}static init(e){let t=e.ele;if(!t)return;let s=!1;if("string"==typeof t){t=document.querySelectorAll(t);const e=t.length;if(0===e)return;1===e&&(s=!0)}void 0!==t.length&&void 0!==t.forEach||(t=[t],s=!0);const i=[];return t.forEach(t=>{t.virtualSelect?i.push(t.virtualSelect):(e.ele=t,"SELECT"===t.tagName&&l.setPropsFromSelect(e),i.push(new l(e)))}),s?i[0]:i}static getAttrProps(){const{convertPropToDataAttr:e}=s,t={};return n.forEach(e=>{t[e]=e}),a.forEach(s=>{t[e(s)]=s}),t}static setPropsFromSelect(e){const t=e.ele,i=[],n=[],a=e=>{const t=[];return Array.from(e.children).forEach(e=>{const{value:s}=e,o={value:s};"OPTGROUP"===e.tagName?(o.label=e.getAttribute("label"),o.options=a(e)):o.label=e.innerHTML,t.push(o),e.disabled&&i.push(s),e.selected&&n.push(s)}),t},l=a(t),h=document.createElement("div");s.setAttrFromEle(t,h,Object.keys(r),o),t.parentNode.insertBefore(h,t),t.remove(),e.ele=h,e.options=l,e.disabledOptions=i,e.selectedValue=n}static onFormReset(e){const t=e.target.closest("form");t&&t.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{e.parentElement.virtualSelect.reset(!0)})}static onFormSubmit(e){l.validate(e.target.closest("form"))||e.preventDefault()}static validate(e){if(!e)return!0;let t=!1;return e.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{const s=e.parentElement.virtualSelect.validate();t||s||(t=!0)}),!t}static reset(e=!1,t=!1){this.virtualSelect.reset(e,t)}static setValueMethod(...e){this.virtualSelect.setValueMethod(...e)}static setOptionsMethod(...e){this.virtualSelect.setOptionsMethod(...e)}static setDisabledOptionsMethod(...e){this.virtualSelect.setDisabledOptionsMethod(...e)}static setEnabledOptionsMethod(...e){this.virtualSelect.setEnabledOptionsMethod(...e)}static toggleSelectAll(e){this.virtualSelect.toggleAllOptions(e)}static isAllSelected(){return this.virtualSelect.isAllSelected}static addOptionMethod(e){this.virtualSelect.addOption(e,!0)}static getNewValueMethod(){return this.virtualSelect.getNewValue()}static getDisplayValueMethod(){return this.virtualSelect.getDisplayValue()}static getSelectedOptionsMethod(e){return this.virtualSelect.getSelectedOptions(e)}static getDisabledOptionsMethod(){return this.virtualSelect.getDisabledOptions()}static openMethod(){return this.virtualSelect.openDropbox()}static closeMethod(){return this.virtualSelect.closeDropbox()}static focusMethod(){return this.virtualSelect.focus()}static enableMethod(){return this.virtualSelect.enable()}static disableMethod(){return this.virtualSelect.disable()}static destroyMethod(){return this.virtualSelect.destroy()}static validateMethod(){return this.virtualSelect.validate()}static toggleRequiredMethod(e){return this.virtualSelect.toggleRequired(e)}static onResizeMethod(){document.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{const t=e.parentElement&&e.parentElement.virtualSelect;t&&t.onResize()})}}l.onResizeThrottled=t.throttle(l.onResizeMethod,100),r=l.getAttrProps(),window.VirtualSelect=l,l.openInstances=new Set,l.domObserver=null,l.activeInstances=new Set,l.hasGlobalListeners=!1,l.lastInteractedInstance=null,l.secureTextWarningShown=!1,"undefined"!=typeof NodeList&&NodeList.prototype&&!NodeList.prototype.forEach&&(NodeList.prototype.forEach=Array.prototype.forEach)}(),function(){"use strict";function e(e){return function(e){if(Array.isArray(e))return t(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,s){if(e){if("string"==typeof e)return t(e,s);var i=Object.prototype.toString.call(e).slice(8,-1);return"Object"===i&&e.constructor&&(i=e.constructor.name),"Map"===i||"Set"===i?Array.from(e):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?t(e,s):void 0}}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function t(e,t){(null==t||t>e.length)&&(t=e.length);for(var s=0,i=new Array(t);ss-o-t.width?"left":"right",vertical:n>i-n-t.height?"top":"bottom"}}},{key:"getAbsoluteCoords",value:function(e){if(e){var t=e.getBoundingClientRect(),s=window.pageXOffset,i=window.pageYOffset;return{width:t.width,height:t.height,top:t.top+i,right:t.right+s,bottom:t.bottom+i,left:t.left+s}}}},{key:"getCoords",value:function(e){return e?e.getBoundingClientRect():{}}},{key:"getData",value:function(e,t,s){if(e){var i=e?e.dataset[t]:"";return"number"===s?i=parseFloat(i)||0:"true"===i?i=!0:"false"===i&&(i=!1),i}}},{key:"setData",value:function(e,t,s){e&&(e.dataset[t]=s)}},{key:"setStyle",value:function(e,t,s){e&&(e.style[t]=s)}},{key:"show",value:function(e){var s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"block";t.setStyle(e,"display",s)}},{key:"hide",value:function(e){t.setStyle(e,"display","none")}},{key:"getHideableParent",value:function(e){for(var t,s=e.parentElement;s;){var i=getComputedStyle(s).overflow;if(-1!==i.indexOf("scroll")||-1!==i.indexOf("auto")){t=s;break}s=s.parentElement}return t}}],s&&function(e,t){for(var s=0;sS?S-b:L:w+p>M&&("right"===E?n="left":w=M+bO?O-u:P:C+c>I&&("bottom"===E?n="top":C=I+up-j&&(G=p-j):"left"!==E&&"right"!==E||((H=f/2+g-R)c-j&&(H=c-j)),s.setStyle(this.$arrowEle,"transform","translate3d(".concat(parseInt(G),"px, ").concat(parseInt(H),"px, 0) ").concat(K))}s.hide(this.$popperEle)}},{key:"resetPosition",value:function(){s.setStyle(this.$popperEle,"transform","none"),this.setPosition()}},{key:"show",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},i=t.resetPosition,o=t.data;clearTimeout(this.exitDelayTimeout),clearTimeout(this.hideDurationTimeout),i&&this.resetPosition(),this.enterDelayTimeout=setTimeout(function(){var t=s.getData(e.$popperEle,"left"),i=s.getData(e.$popperEle,"top"),n="translate3d(".concat(parseInt(t),"px, ").concat(parseInt(i),"px, 0)"),r=e.showDuration;s.show(e.$popperEle,"inline-flex"),s.getCoords(e.$popperEle),s.setStyle(e.$popperEle,"transitionDuration",r+"ms"),s.setStyle(e.$popperEle,"transform",n),s.setStyle(e.$popperEle,"opacity",1),e.showDurationTimeout=setTimeout(function(){"function"==typeof e.afterShowCallback&&e.afterShowCallback(o)},r)},this.enterDelay)}},{key:"hide",value:function(){var e=this,t=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).data;clearTimeout(this.enterDelayTimeout),clearTimeout(this.showDurationTimeout),this.exitDelayTimeout=setTimeout(function(){if(e.$popperEle){var i=parseInt(s.getData(e.$popperEle,"fromLeft")),o=parseInt(s.getData(e.$popperEle,"fromTop")),n="translate3d(".concat(i,"px, ").concat(o,"px, 0)"),r=e.hideDuration;s.setStyle(e.$popperEle,"transitionDuration",r+"ms"),s.setStyle(e.$popperEle,"transform",n),s.setStyle(e.$popperEle,"opacity",0),e.hideDurationTimeout=setTimeout(function(){s.hide(e.$popperEle),"function"==typeof e.afterHideCallback&&e.afterHideCallback(t)},r)}},this.exitDelay)}},{key:"updatePosition",value:function(){s.setStyle(this.$popperEle,"transitionDuration","0ms"),this.resetPosition();var e=parseInt(s.getData(this.$popperEle,"left")),t=parseInt(s.getData(this.$popperEle,"top"));s.show(this.$popperEle,"inline-flex"),s.setStyle(this.$popperEle,"transform","translate3d(".concat(e,"px, ").concat(t,"px, 0)"))}}],t&&function(e,t){for(var s=0;s1&&void 0!==arguments[1]&&arguments[1]}},{key:"removeArrayEmpty",value:function(e){return Array.isArray(e)&&e.length?e.filter(function(e){return!!e}):[]}},{key:"throttle",value:function(e,t){var s,i=0;return function(){for(var o=arguments.length,n=new Array(o),r=0;re.length)&&(t=e.length);for(var s=0,i=new Array(t);s'),e=this.$popover.querySelector(".pop-comp-arrow")),this.$arrowEle=e}}},{key:"destroy",value:function(){this.removeEvents()}}])&&c(t.prototype,s),o&&c(t,o),Object.defineProperty(t,"prototype",{writable:!1}),t;var t,s,o}();d=m.getAttrProps(),window.PopoverComponent=m}(); + */!function(){"use strict";const e=/[^\p{L}\p{N}_]/gu;class t{static getString(e){return e||0===e?e.toString():""}static convertToBoolean(e,t=!1){let s;return s=!0===e||"true"===e||!1!==e&&"false"!==e&&t,s}static isEmpty(e){let t=!1;return e?Array.isArray(e)?0===e.length&&(t=!0):"object"==typeof e&&0===Object.keys(e).length&&(t=!0):t=!0,t}static isNotEmpty(e){return!t.isEmpty(e)}static normalizeValues(e){if(Array.isArray(e)){const t=new Array(e.length);for(let s=0;s!!e):[]}static getRandomInt(e,t=0){const s=Math.ceil(t),i=Math.floor(e);return Math.floor(Math.random()*(i-s-1))+s}static regexEscape(e){return e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}static normalizeString(t){return t.normalize("NFD").replace(e,"")}static prefersReducedMotion(){return"function"==typeof window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}static replaceDoubleQuotesWithHTML(e){return e.replace(/"/g,""")}static escapeAttributeValue(e){return t.getString(e).replace(/&/g,"&").replace(/"/g,""")}static decodeSecureText(e){return t.getString(e).replace(/</g,"<").replace(/>/g,">").replace(/ /g," ").replace(/&/g,"&")}static getPlainText(e){return t.decodeSecureText(e).replace(/<[^>]+>/gi," ").replace(/\s+/g," ").trim()}static getAriaLabelText(e){return t.escapeAttributeValue(t.getPlainText(e))}static containsHTML(e){return/<[a-z][\s\S]*>/i.test(e)}static containsHTMLorJS(e){return/<([a-z]+)[\s\S]*?>|on\w+="[^"]*"/i.test(e)}static sanitizeClassNames(e){return e?String(e).replace(/["<>]/g,""):e}static throttle(e,t){let s,i=null,o=[],n=0;function r(){const t=s,i=o;o=[],s=void 0,e.apply(t,i)}function a(...e){const a=Date.now(),l=t-(a-n);o=e,s=this,l<=0||l>t?(i&&(clearTimeout(i),i=null),n=a,r()):i||(i=setTimeout(()=>{n=Date.now(),i=null,r()},l))}return a.cancel=function(){i&&(clearTimeout(i),i=null),n=0,o=[],s=void 0},a}}class s{static addClass(e,t){if(!e)return;const i=t.split(" ");s.getElements(e).forEach(e=>{e.classList.add(...i)})}static removeClass(e,t){if(!e)return;const i=t.split(" ");s.getElements(e).forEach(e=>{e.classList.remove(...i)})}static toggleClass(e,t,i){if(!e)return;let o;void 0!==i&&(o=Boolean(i)),s.getElements(e).forEach(e=>{e.classList.toggle(t,o)})}static hasClass(e,t){return!!e&&e.classList.contains(t)}static hasEllipsis(e){return!!e&&e.scrollWidth>e.offsetWidth}static getData(e,t,s){if(!e)return;let i=e?e.dataset[t]:"";return"number"===s?i=parseFloat(i)||0:"true"===i?i=!0:"false"===i&&(i=!1),i}static setData(e,t,s){e&&(e.dataset[t]=s)}static setAttr(e,t,s){e&&e.setAttribute(t,s)}static removeAttr(e,t){e&&e.removeAttribute(t)}static toggleAria(e,t,i,o="true"){e&&s.getElements(e).forEach(e=>{i?e.setAttribute(`aria-${t}`,o):e.removeAttribute(`aria-${t}`)})}static setAttrFromEle(e,t,s,i){const o={};s.forEach(t=>{o[t]=e.getAttribute(t)}),s.forEach(e=>{const s=o[e];(s||-1!==i.indexOf(e)&&""===s)&&t.setAttribute(e,s)})}static setStyle(e,t,s){e&&(e.style[t]=s)}static setStyles(e,t){e&&t&&Object.keys(t).forEach(s=>{e.style[s]=t[s]})}static setAria(e,t,s){if(!e)return;let i=t;"role"!==i&&(i=`aria-${i}`),e.setAttribute(i,s)}static getElements(e){return e?void 0===e.forEach?[e]:e:[]}static getElementsBySelector(e="",t=void 0){let s;const i=void 0!==t?t:document;return""!==e&&(s=i.querySelectorAll(e)),void 0!==s?Array.from(s):[]}static addEvent(e,i,o,n){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{s.getElements(e).forEach(e=>{e.addEventListener(t,o,{capture:n})})})}static dispatchEvent(e,t,i=!1){if(!e)return;const o=s.getElements(e);setTimeout(()=>{o.forEach(e=>{e.dispatchEvent(new CustomEvent(t,{bubbles:i}))})},0)}static getAttributesText(e){let s="";return e?(Object.entries(e).forEach(([e,i])=>{void 0!==i&&(s+=` ${e}="${t.replaceDoubleQuotesWithHTML(String(i))}" `)}),s):s}static convertPropToDataAttr(e){return e?`data-${e}`.replace(/([A-Z])/g,"-$1").toLowerCase():""}static changeTabIndex(e,t){e?s.getElements(e).forEach(e=>{e.tabIndex=t}):console.log(e,"Invalid element provided.")}static removeEvent(e,t,i,o=!1){e&&s.getElements(e).forEach(e=>{e.removeEventListener(t,i,{capture:o})})}}const i={13:"onEnterPress",38:"onUpArrowPress",40:"onDownArrowPress",46:"onBackspaceOrDeletePress",8:"onBackspaceOrDeletePress"},o=["autofocus","disabled","multiple","required"],n=["autofocus","class","disabled","id","multiple","name","placeholder","required"];let r;const a=["additionalClasses","additionalDropboxClasses","additionalDropboxContainerClasses","additionalToggleButtonClasses","aliasKey","allOptionsSelectedText","allowNewOption","alwaysShowSelectedOptionsCount","alwaysShowSelectedOptionsLabel","ariaLabelledby","ariaLabelText","ariaLabelClearButtonText","ariaLabelTagClearButtonText","ariaLabelSearchClearButtonText","autoSelectFirstOption","clearButtonText","descriptionKey","disableAllOptionsSelectedText","disableOptionGroupCheckbox","disableSelectAll","disableValidation","dropboxWidth","dropboxWrapper","emptyValue","enableSecureText","focusSelectedOptionOnOpen","hasOptionDescription","hideClearButton","hideValueTooltipOnSelectAll","keepAlwaysOpen","labelKey","markSearchResults","maxValues","maxWidth","minValues","loadingText","minValuesErrorText","moreText","noOfDisplayValues","noOptionsSelectedText","noOptionsText","noSearchResultsText","optionHeight","optionSelectedText","optionsCount","optionsSelectedText","popupDropboxBreakpoint","popupPosition","position","requiredErrorText","search","searchByStartsWith","searchDelay","searchFormLabel","searchGroup","searchNormalize","searchPlaceholderText","searchResultText","searchResultsText","selectAllOnlyVisible","selectAllText","selectedText","setValueAsArray","showDropboxAsPopup","showOptionsOnlyOnSearch","showSecureTextWarning","showSelectedOptionsFirst","showValueAsTags","silentInitialValueSet","textDirection","tooltipAlignment","tooltipFontSize","tooltipMaxWidth","updatePositionThrottle","useGroupValue","valueKey","zIndex"];class l{constructor(e){this.isDestroyed=!1;try{this.createSecureTextElements(),this.setProps(e),this.setDisabledOptions(e.disabledOptions),this.setOptions(e.options),this.warnIfSecureTextDisabled(),this.render()}catch(e){console.warn("Couldn't initiate Virtual Select"),console.error(e)}}render(){if(!this.$ele)return;const{uniqueId:e}=this;let i="vscomp-wrapper",o="vscomp-toggle-button";const n=this.showValueAsTags?"":this.getTooltipAttrText(this.placeholder,!0,!0),r=this.getTooltipAttrText(this.clearButtonText),a=this.ariaLabelledby?`aria-labelledby="${t.replaceDoubleQuotesWithHTML(t.getString(this.ariaLabelledby))}"`:"",l=this.ariaLabelText?`aria-label="${t.getAriaLabelText(this.ariaLabelText)}"`:"",h=this.ariaLabelClearButtonText?`aria-label="${t.getAriaLabelText(this.ariaLabelClearButtonText)}"`:"";let p=!1;this.additionalClasses&&(i+=` ${t.sanitizeClassNames(this.additionalClasses)}`),this.additionalToggleButtonClasses&&(o+=` ${t.sanitizeClassNames(this.additionalToggleButtonClasses)}`),this.multiple&&(i+=" multiple",this.disableSelectAll||(i+=" has-select-all")),this.hideClearButton||(i+=" has-clear-button"),this.keepAlwaysOpen?(i+=" keep-always-open",p=!0):i+=" closed",this.showAsPopup&&(i+=" show-as-popup"),this.hasSearch&&(i+=" has-search-input"),this.showValueAsTags&&(i+=" show-value-as-tags"),this.textDirection&&(i+=` text-direction-${this.textDirection}`),this.popupPosition&&(i+=` popup-position-${this.popupPosition.toLowerCase()}`);const c=`
\n \n
\n
\n ${this.placeholder}\n
\n
\n
\n \n
\n
\n\n ${this.renderDropbox({wrapperClasses:i})}\n
\n\n
\n\n
`;this.$ele.innerHTML=c,this.$body=document.querySelector("body"),this.$wrapper=this.$ele.querySelector(".vscomp-wrapper"),this.hasDropboxWrapper?(this.$allWrappers=[this.$wrapper,this.$dropboxWrapper],this.$dropboxContainer=this.$dropboxWrapper.querySelector(".vscomp-dropbox-container"),s.addClass(this.$dropboxContainer,"pop-comp-wrapper")):(this.$allWrappers=[this.$wrapper],this.$dropboxContainer=this.$wrapper.querySelector(".vscomp-dropbox-container")),this.$toggleButton=this.$ele.querySelector(".vscomp-toggle-button"),this.$clearButton=this.$ele.querySelector(".vscomp-clear-button"),this.$valueText=this.$ele.querySelector(".vscomp-value"),this.$hiddenInput=this.$ele.querySelector(".vscomp-hidden-input"),this.$hiddenInput.name=this.name,this.$liveRegion=this.$ele.querySelector(".vscomp-live-region"),this.$errorMessage=this.$ele.querySelector(".vscomp-error-message"),this.$dropbox=this.$dropboxContainer.querySelector(".vscomp-dropbox"),this.$dropboxCloseButton=this.$dropboxContainer.querySelector(".vscomp-dropbox-close-button"),this.$dropboxContainerBottom=this.$dropboxContainer.querySelector(".vscomp-dropbox-container-bottom"),this.$dropboxContainerTop=this.$dropboxContainer.querySelector(".vscomp-dropbox-container-top"),this.$search=this.$dropboxContainer.querySelector(".vscomp-search-wrapper"),this.$optionsContainer=this.$dropboxContainer.querySelector(".vscomp-options-container"),this.$optionsList=this.$dropboxContainer.querySelector(".vscomp-options-list"),this.$options=this.$dropboxContainer.querySelector(".vscomp-options"),this.$noOptions=this.$dropboxContainer.querySelector(".vscomp-no-options"),this.$noSearchResults=this.$dropboxContainer.querySelector(".vscomp-no-search-results"),this.afterRenderWrapper()}renderDropbox({wrapperClasses:e}){const i="self"!==this.dropboxWrapper?document.querySelector(this.dropboxWrapper):null;let o="vscomp-dropbox";this.additionalDropboxClasses&&(o+=` ${t.sanitizeClassNames(this.additionalDropboxClasses)}`);let n="vscomp-dropbox-container";this.additionalDropboxContainerClasses&&(n+=` ${t.sanitizeClassNames(this.additionalDropboxContainerClasses)}`);const r=`
\n \n
\n
\n\n
\n
\n\n
\n
\n
\n
\n\n
\n
${this.noOptionsText}
\n
${this.noSearchResultsText}
\n\n \n
\n \n
`;if(i){const t=document.createElement("div");return this.$dropboxWrapper=t,this.hasDropboxWrapper=!0,t.innerHTML=r,i.appendChild(t),s.addClass(t,`vscomp-dropbox-wrapper ${e}`),this.keepAlwaysOpen||(s.setAttr(t,"tabindex","-1"),s.setAria(t,"hidden",!0)),""}return this.hasDropboxWrapper=!1,r}renderOptions(){this.ariaMetadataDirty&&(this.calculateAriaMetadata(),this.ariaMetadataDirty=!1);let e="";const s=this.getVisibleOptions();let i="",o="";const n=!(!this.markSearchResults||!this.searchValue);let r;const{labelRenderer:a,disableOptionGroupCheckbox:l,uniqueId:h,searchGroup:p}=this,c="function"==typeof a,{convertToBoolean:u}=t;let d="";if(n&&(r=new RegExp(`(${t.regexEscape(this.searchValue)})(?!([^<]+)?>)`,"gi")),this.multiple&&(i=''),this.allowNewOption){const e=this.getTooltipAttrText("New Option");o=``}s.forEach(s=>{const{index:v}=s;let b,m="vscomp-option";const g=this.getTooltipAttrText("",!0,!0);let f=i,x="",S="",O="",y="",$="-1";const w=u(s.isSelected);let C="";if(s.classNames&&(m+=` ${t.sanitizeClassNames(s.classNames)}`),s.isFocused&&($="0",m+=" focused"),s.isDisabled&&(m+=" disabled",C='aria-disabled="true"'),s.isGroupTitle)if(d=t.getAriaLabelText(s.label),m+=" group-title",l)f="";else if(this.multiple){const e=t.getAriaLabelText(this.selectAllText);y=`aria-label="${d}, ${e}"`}if(w&&(m+=" selected"),s.isGroupOption)if(m+=" group-option",O=`data-group-index="${s.groupIndex}"`,s.customData){const e=t.getAriaLabelText(this.secureText(t.getString(s.customData.group_name))),i=t.getAriaLabelText(this.secureText(t.getString(s.customData.description)));d=void 0!==s.customData.group_name?`${e}, `:"";const o=void 0!==s.customData.description?` ${i},`:"";y=`aria-label="${d} ${t.getAriaLabelText(s.label)}, ${o}"`}else y=`aria-label="${d}, ${t.getAriaLabelText(s.label)}"`;b=c?a(s):s.label,s.description&&(S=`
${s.description}
`),s.isCurrentNew?(m+=" current-new",x+=o):!n||s.isGroupTitle&&!p||(b=b.replace(r,"$1"));let T="";this.ariaSetSize>0&&(T=`aria-setsize="${this.ariaSetSize}"`,s.filteredIndex&&(T+=` aria-posinset="${s.filteredIndex}"`));const E=t.escapeAttributeValue(s.value);e+=`
\n ${f}\n \n ${b}\n \n ${S}\n ${x}\n
`}),d="",this.$options.innerHTML=e,this.$visibleOptions=this.$options.querySelectorAll(".vscomp-option"),this.afterRenderOptions()}renderSearch(){if(!this.hasSearchContainer)return;let e="",s="";if(this.multiple&&!this.disableSelectAll&&(e=`\n \n ${this.selectAllText}\n `),this.hasSearch){const e=this.ariaLabelSearchClearButtonText?`aria-label="${t.getAriaLabelText(this.ariaLabelSearchClearButtonText)}"`:"";s=`\n \n ×`}const i=`
\n ${e}\n ${s}\n
`;this.$search.innerHTML=i,this.$searchInput=this.$dropboxContainer.querySelector(".vscomp-search-input"),this.$searchClear=this.$dropboxContainer.querySelector(".vscomp-search-clear"),this.$toggleAllButton=this.$dropboxContainer.querySelector(".vscomp-toggle-all-button"),this.$toggleAllCheckbox=this.$dropboxContainer.querySelector(".vscomp-toggle-all-checkbox"),this.addEvent(this.$searchInput,"input","onSearch"),this.addEvent(this.$searchInput,"change","preventPropagation"),this.addEvent(this.$searchClear,"click keydown","onSearchClear"),this.addEvent(this.$toggleAllButton,"click","onToggleAllOptions"),this.addEvent(this.$dropboxContainerBottom,"focus","onDropboxContainerTopOrBottomFocus"),this.addEvent(this.$dropboxContainerTop,"focus","onDropboxContainerTopOrBottomFocus")}addEvents(){this.addEvent(document,"click","onDocumentClick",!0),this.addEvent(this.$allWrappers,"keydown","onKeyDown"),this.addEvent(this.$toggleButton,"click keydown","onToggleButtonPress"),this.addEvent(this.$clearButton,"click keydown","onClearButtonClick"),this.addEvent(this.$dropboxContainer,"click","onDropboxContainerClick"),this.addEvent(this.$dropboxCloseButton,"click","onDropboxCloseButtonClick"),this.addEvent(this.$optionsContainer,"scroll","onOptionsScroll"),this.addEvent(this.$options,"click","onOptionsClick"),this.addEvent(this.$options,"mouseover","onOptionsMouseOver"),this.addEvent(this.$options,"touchmove","onOptionsTouchMove"),l.registerInstance(this)}addEvent(e,i,o,n=!1){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{const i=`${o}-${t}`;let r=this.events[i];r||(r=this[o].bind(this),this.events[i]=r),s.addEvent(e,t,r,n)})}removeEvents(){this.removeEvent(document,"click","onDocumentClick",!0),this.removeEvent(this.$allWrappers,"keydown","onKeyDown"),this.removeEvent(this.$toggleButton,"click keydown","onToggleButtonPress"),this.removeEvent(this.$clearButton,"click keydown","onClearButtonClick"),this.removeEvent(this.$dropboxContainer,"click","onDropboxContainerClick"),this.removeEvent(this.$dropboxCloseButton,"click","onDropboxCloseButtonClick"),this.removeEvent(this.$optionsContainer,"scroll","onOptionsScroll"),this.removeEvent(this.$options,"click","onOptionsClick"),this.removeEvent(this.$options,"mouseover","onOptionsMouseOver"),this.removeEvent(this.$options,"touchmove","onOptionsTouchMove"),this.$searchInput&&(this.removeEvent(this.$searchInput,"input","onSearch"),this.removeEvent(this.$searchInput,"change","preventPropagation"),this.$searchClear&&(this.removeEvent(this.$searchClear,"click","onSearchClear"),this.removeEvent(this.$searchClear,"keydown","onSearchClear"))),this.$toggleAllButton&&this.removeEvent(this.$toggleAllButton,"click","onToggleAllOptions"),this.$dropboxContainerBottom&&this.removeEvent(this.$dropboxContainerBottom,"focus","onDropboxContainerTopOrBottomFocus"),this.$dropboxContainerTop&&this.removeEvent(this.$dropboxContainerTop,"focus","onDropboxContainerTopOrBottomFocus")}removeEvent(e,i,o,n=!1){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{const i=`${o}-${t}`,r=this.events[i];r&&s.removeEvent(e,t,r,n)})}onDocumentClick(e){const t=e.target.closest(".vscomp-wrapper");if(!t)return void l.openInstances.forEach(e=>{const t=e;t.shouldFocusWrapperOnClose=!1,t.closeDropbox()});const s=t.parentElement.virtualSelect;s&&s!==this&&this.isOpened()&&!this.keepAlwaysOpen&&(this.shouldFocusWrapperOnClose=!1,this.closeDropbox())}onKeyDown(e){const t=e.which||e.keyCode,s=i[t];if(document.activeElement!==this.$searchInput||e.shiftKey||9!==t||this.multiple||(e.preventDefault(),this.focusFirstVisibleOption()),document.activeElement===this.$toggleAllButton&&(13===t||32===t))return e.preventDefault(),void this.toggleAllOptions();if(27===t||"Escape"===e.key){const e=this.hasDropboxWrapper&&!this.showAsPopup?this.$dropboxWrapper:this.$wrapper;if(e&&(document.activeElement===e||e.contains(document.activeElement))&&!this.keepAlwaysOpen)return void this.closeDropbox()}s&&this[s](e)}onEnterPress(e){e.preventDefault(),this.isOpened()?this.selectFocusedOption():!1===this.$ele.disabled&&this.openDropbox()}navigateOptions(e,t){e.preventDefault(),this.isOpened()?this.focusOption({direction:t}):this.openDropbox()}onDownArrowPress(e){this.navigateOptions(e,"next")}onUpArrowPress(e){this.navigateOptions(e,"previous")}onBackspaceOrDeletePress(e){e.target===this.$wrapper&&(e.preventDefault(),this.selectedValues.length>0&&this.reset())}onToggleButtonPress(e){if("keydown"===e.type){if("Enter"!==e.code&&"Space"!==e.code)return;e.preventDefault()}const t=e.target;if(t.closest(".vscomp-value-tag-clear-button"))return e.stopPropagation(),void this.removeValue(t.closest(".vscomp-value-tag"));t.closest(".toggle-button-child")||this.toggleDropbox()}onClearButtonClick(e){"click"===e.type?this.reset():"keydown"!==e.type||"Enter"!==e.code&&"Space"!==e.code||(e.stopPropagation(),this.reset())}onOptionsScroll(){this.scrollAnimationFrame||(this.scrollAnimationFrame=requestAnimationFrame(()=>{this.scrollAnimationFrame=null,this.isDestroyed||this.setVisibleOptions(!0)}))}onOptionsClick(e){const t=e.target.closest(".vscomp-option");t&&!s.hasClass(t,"disabled")&&(s.hasClass(t,"group-title")?this.onGroupTitleClick(t):this.selectOption(t,{event:e}))}onGroupTitleClick(e){if(!e||!this.multiple||this.disableOptionGroupCheckbox)return;const t=!s.hasClass(e,"selected");this.toggleGroupTitleCheckbox(e,t),this.toggleGroupOptions(e,t)}onDropboxContainerClick(e){e.target.closest(".vscomp-dropbox")||this.closeDropbox()}onDropboxCloseButtonClick(){this.closeDropbox()}onOptionsMouseOver(e){const t=e.target.closest(".vscomp-option");t&&this.isOpened()&&(this.shouldSkipOptionInNavigation(t)?this.removeOptionFocus():this.focusOption({$option:t}))}onOptionsTouchMove(){this.removeOptionFocus()}onSearch(e){e.stopPropagation(),this.setSearchValue(e.target.value,!0)}preventPropagation(e){e.stopPropagation()}onSearchClear(e){e.stopPropagation(),"Enter"!==e.code&&"Space"!==e.code&&"click"!==e.type||(this.setSearchValue(""),this.focusSearchInput())}onToggleAllOptions(){this.toggleAllOptions()}onDropboxContainerTopOrBottomFocus(){this.closeDropbox()}onResize(){this.setOptionsContainerHeight(!0)}static observeDomChanges(){l.domObserver||(l.domObserver=new MutationObserver(e=>{e.forEach(e=>{e.removedNodes.forEach(e=>{if(e.nodeType!==Node.ELEMENT_NODE)return;const t=e.classList.contains("vscomp-ele")?[e]:[];e.querySelectorAll(".vscomp-ele").forEach(e=>t.push(e)),t.forEach(e=>{!e.isConnected&&e.virtualSelect&&e.virtualSelect.destroy()})})})}),l.domObserver.observe(document.documentElement,{childList:!0,subtree:!0}))}static disconnectDomObserver(){l.domObserver&&(l.domObserver.disconnect(),l.domObserver=null)}static addGlobalListeners(){l.hasGlobalListeners||(document.addEventListener("reset",l.onFormReset),document.addEventListener("submit",l.onFormSubmit),window.addEventListener("resize",l.onResizeThrottled),l.hasGlobalListeners=!0)}static removeGlobalListeners(){l.hasGlobalListeners&&(document.removeEventListener("reset",l.onFormReset),document.removeEventListener("submit",l.onFormSubmit),window.removeEventListener("resize",l.onResizeThrottled),l.onResizeThrottled&&"function"==typeof l.onResizeThrottled.cancel&&l.onResizeThrottled.cancel(),l.hasGlobalListeners=!1)}static registerInstance(e){l.activeInstances.add(e),l.addGlobalListeners(),l.observeDomChanges()}static unregisterInstance(e){l.activeInstances.delete(e),0===l.activeInstances.size&&(l.removeGlobalListeners(),l.disconnectDomObserver())}beforeValueSet(e){this.toggleAllOptionsClass(!e&&void 0)}beforeSelectNewValue(e){const t=this.getNewOption();if(t){const e=t.index;this.newValues.push(t.value),this.setOptionProp(e,"isCurrentNew",!1),this.setOptionProp(e,"isNew",!0)}else e&&(this.setNewOption(e),this.toggleSelectedProp(this.lastOptionIndex,!0));this.setManagedTimeout(()=>{this.setSearchValue(""),this.focusSearchInput()},0)}afterRenderWrapper(){s.addClass(this.$ele,"vscomp-ele"),this.renderSearch(),this.setEleStyles(),this.setDropboxStyles(),this.setVisibleOptionsCount(),this.setOptionsContainerHeight(),this.addEvents();try{this.setEleProps(),this.keepAlwaysOpen||this.showAsPopup||this.initDropboxPopover(),this.initialSelectedValue?this.setValueMethod(this.initialSelectedValue,this.silentInitialValueSet):this.autoSelectFirstOption&&this.visibleOptions.length&&this.setValueMethod(this.visibleOptions[0].value,this.silentInitialValueSet),this.showOptionsOnlyOnSearch&&this.setSearchValue("",!1,!0),this.initialDisabled&&this.disable(),this.autofocus&&this.focus(),this.isInitialized=!0}catch(e){throw this.destroy(),e}}afterRenderOptions(){const e=this.getVisibleOptions(),t=!this.options.length&&!this.hasServerSearch,i=!t&&!e.length;(!this.allowNewOption||this.hasServerSearch||this.showOptionsOnlyOnSearch)&&(s.toggleClass(this.$allWrappers,"has-no-search-results",i),i?(s.setAttr(this.$noSearchResults,"tabindex","0"),s.setAttr(this.$noSearchResults,"aria-hidden","false")):(s.setAttr(this.$noSearchResults,"tabindex","-1"),s.setAttr(this.$noSearchResults,"aria-hidden","true"))),s.toggleClass(this.$allWrappers,"has-no-options",t),t?(s.setAttr(this.$noOptions,"tabindex","0"),s.setAttr(this.$noOptions,"aria-hidden","false")):(s.setAttr(this.$noOptions,"tabindex","-1"),s.setAttr(this.$noOptions,"aria-hidden","true")),this.setOptionAttr(),this.setOptionsPosition(),this.setOptionsTooltip(),document.activeElement!==this.$searchInput&&this.setManagedTimeout(()=>{const e=s.getElementsBySelector(".focused",this.$dropboxContainer)[0];void 0!==e&&e.focus({preventScroll:!0})},20)}afterSetOptionsContainerHeight(e){e&&this.showAsPopup&&this.setVisibleOptions()}afterSetSearchValue(){this.hasServerSearch?(clearTimeout(this.serverSearchTimeout),this.isSilentServerSearch=!1,this.serverSearchTimeout=setTimeout(()=>{this.serverSearch()},this.searchDelay)):this.setVisibleOptionsCount(),this.selectAllOnlyVisible&&this.toggleAllOptionsClass(),this.isClosing||this.focusOption({focusFirst:!0}),this.hasServerSearch||this.announceSearchResults()}afterSetVisibleOptionsCount(){this.scrollToTop(),this.setOptionsHeight(),this.setVisibleOptions(),this.updatePosition()}afterValueSet(){this.scrollToTop(),this.setSearchValue(""),this.renderOptions()}afterSetOptions(e){if(e&&this.setSelectedProp(),this.setOptionsHeight(),this.setVisibleOptions(),this.showOptionsOnlyOnSearch&&this.setSearchValue("",!1,!0),!e){this.isRefreshingOptions=!0;try{this.reset()}finally{this.isRefreshingOptions=!1}}}setProps(e){const s=this.setDefaultProps(e);this.setPropsFromElementAttr(s);const{convertToBoolean:i}=t;this.$ele=s.ele,this.dropboxWrapper=s.dropboxWrapper,this.valueKey=s.valueKey,this.labelKey=s.labelKey,this.descriptionKey=s.descriptionKey,this.aliasKey=s.aliasKey,this.optionHeightText=s.optionHeight,this.optionHeight=parseFloat(this.optionHeightText),this.multiple=i(s.multiple),this.hasSearch=i(s.search),this.searchByStartsWith=i(s.searchByStartsWith),this.searchGroup=i(s.searchGroup),this.hideClearButton=i(s.hideClearButton),this.autoSelectFirstOption=i(s.autoSelectFirstOption),this.hasOptionDescription=i(s.hasOptionDescription),this.silentInitialValueSet=i(s.silentInitialValueSet),this.allowNewOption=i(s.allowNewOption),this.markSearchResults=i(s.markSearchResults),this.showSelectedOptionsFirst=i(s.showSelectedOptionsFirst),this.disableSelectAll=i(s.disableSelectAll),this.keepAlwaysOpen=i(s.keepAlwaysOpen),this.showDropboxAsPopup=i(s.showDropboxAsPopup),this.hideValueTooltipOnSelectAll=i(s.hideValueTooltipOnSelectAll),this.showOptionsOnlyOnSearch=i(s.showOptionsOnlyOnSearch),this.selectAllOnlyVisible=i(s.selectAllOnlyVisible),this.alwaysShowSelectedOptionsCount=i(s.alwaysShowSelectedOptionsCount),this.alwaysShowSelectedOptionsLabel=i(s.alwaysShowSelectedOptionsLabel),this.disableAllOptionsSelectedText=i(s.disableAllOptionsSelectedText),this.showValueAsTags=i(s.showValueAsTags),this.disableOptionGroupCheckbox=i(s.disableOptionGroupCheckbox),this.enableSecureText=i(s.enableSecureText),this.showSecureTextWarning=i(s.showSecureTextWarning,!0),this.setValueAsArray=i(s.setValueAsArray),this.disableValidation=i(s.disableValidation),this.initialDisabled=i(s.disabled),this.required=i(s.required),this.autofocus=i(s.autofocus),this.useGroupValue=i(s.useGroupValue),this.focusSelectedOptionOnOpen=i(s.focusSelectedOptionOnOpen),this.noOptionsText=s.noOptionsText,this.noSearchResultsText=s.noSearchResultsText,this.selectAllText=s.selectAllText,this.searchNormalize=s.searchNormalize,this.searchPlaceholderText=s.searchPlaceholderText,this.searchFormLabel=s.searchFormLabel,this.optionsSelectedText=s.optionsSelectedText,this.optionSelectedText=s.optionSelectedText,this.allOptionsSelectedText=s.allOptionsSelectedText,this.searchResultsText=s.searchResultsText,this.searchResultText=s.searchResultText,this.noOptionsSelectedText=s.noOptionsSelectedText,this.selectedText=s.selectedText,this.loadingText=s.loadingText,this.requiredErrorText=s.requiredErrorText,this.minValuesErrorText=s.minValuesErrorText,this.clearButtonText=s.clearButtonText,this.moreText=s.moreText,this.placeholder=s.placeholder,this.position=s.position,this.textDirection=s.textDirection,this.dropboxWidth=s.dropboxWidth,this.tooltipFontSize=s.tooltipFontSize,this.tooltipAlignment=s.tooltipAlignment,this.tooltipMaxWidth=s.tooltipMaxWidth,this.updatePositionThrottle=s.updatePositionThrottle,this.noOfDisplayValues=parseInt(s.noOfDisplayValues,10),this.zIndex=parseInt(s.zIndex,10),this.maxValues=parseInt(s.maxValues,10),this.minValues=parseInt(s.minValues,10),this.name=s.name,this.additionalClasses=s.additionalClasses,this.additionalDropboxClasses=s.additionalDropboxClasses,this.additionalDropboxContainerClasses=s.additionalDropboxContainerClasses,this.additionalToggleButtonClasses=s.additionalToggleButtonClasses,this.popupDropboxBreakpoint=s.popupDropboxBreakpoint,this.popupPosition=s.popupPosition,this.onServerSearch=s.onServerSearch,this.labelRenderer=s.labelRenderer,this.selectedLabelRenderer=s.selectedLabelRenderer,this.initialSelectedValue=0===s.selectedValue?"0":s.selectedValue,this.emptyValue=s.emptyValue,this.ariaLabelText=s.ariaLabelText,this.ariaLabelledby=s.ariaLabelledby,this.ariaLabelClearButtonText=s.ariaLabelClearButtonText,this.ariaLabelTagClearButtonText=s.ariaLabelTagClearButtonText,this.ariaLabelSearchClearButtonText=s.ariaLabelSearchClearButtonText,this.maxWidth=s.maxWidth,this.searchDelay=s.searchDelay,this.showDuration=parseInt(s.showDuration,10),this.hideDuration=parseInt(s.hideDuration,10),t.prefersReducedMotion()&&(this.showDuration=0,this.hideDuration=0),this.selectedValues=[],this.selectedOptions=[],this.newValues=[],this.events={},this.tooltipEnterDelay=200,this.searchValue="",this.searchValueOriginal="",this.isAllSelected=!1,(void 0===s.search&&this.multiple||this.allowNewOption||this.showOptionsOnlyOnSearch)&&(this.hasSearch=!0),this.hasServerSearch="function"==typeof this.onServerSearch,(this.maxValues||this.hasServerSearch||this.showOptionsOnlyOnSearch)&&(this.disableSelectAll=!0,this.disableOptionGroupCheckbox=!0),this.keepAlwaysOpen&&(this.dropboxWrapper="self"),this.showAsPopup=this.showDropboxAsPopup&&!this.keepAlwaysOpen&&window.innerWidth<=parseFloat(this.popupDropboxBreakpoint),this.hasSearchContainer=this.hasSearch||this.multiple&&!this.disableSelectAll,this.optionsCount=this.getOptionsCount(s.optionsCount),this.halfOptionsCount=Math.ceil(this.optionsCount/2),this.optionsHeight=this.getOptionsHeight(),this.uniqueId=this.getUniqueId(),this.shouldFocusWrapperOnClose=!0,this.isClosing=!1,this.isSilentServerSearch=!1,this.ariaSetSize=0,this.ariaMetadataDirty=!0}setDefaultProps(e){const t=l.globalDefaults,s=s=>void 0!==e[s]?e[s]:t[s],i={dropboxWrapper:"self",valueKey:"value",labelKey:"label",descriptionKey:"description",aliasKey:"alias",ariaLabelText:"Options list",ariaLabelClearButtonText:"Clear button",ariaLabelTagClearButtonText:"Remove option",ariaLabelSearchClearButtonText:"Clear search input",optionsCount:5,noOfDisplayValues:50,optionHeight:"40px",noOptionsText:"No options found",noSearchResultsText:"No results found",selectAllText:"Select All",searchNormalize:!1,searchPlaceholderText:"Search...",searchFormLabel:"Search",clearButtonText:"Clear",moreText:"more...",optionsSelectedText:"options selected",optionSelectedText:"option selected",searchResultsText:"results available",searchResultText:"result available",noOptionsSelectedText:"No options selected",selectedText:"selected",loadingText:"Loading results",requiredErrorText:"This field is required",minValuesErrorText:"Select at least {count} options",allOptionsSelectedText:"All",placeholder:"Select",position:"bottom left",zIndex:s("keepAlwaysOpen")?1:2,tooltipFontSize:"14px",tooltipAlignment:"center",tooltipMaxWidth:"300px",updatePositionThrottle:100,name:"",additionalClasses:"",additionalDropboxClasses:"",additionalDropboxContainerClasses:"",additionalToggleButtonClasses:"",maxValues:0,showDropboxAsPopup:!0,showSecureTextWarning:!0,popupDropboxBreakpoint:"576px",popupPosition:"center",hideValueTooltipOnSelectAll:!0,emptyValue:"",searchDelay:300,focusSelectedOptionOnOpen:!0,showDuration:300,hideDuration:200};s("hasOptionDescription")&&(i.optionsCount=4,i.optionHeight="50px");const o=e=>{const t={};return Object.keys(e||{}).forEach(s=>{void 0!==e[s]&&(t[s]=e[s])}),t};return Object.assign(i,o(t),o(e))}setPropsFromElementAttr(e){const t=e.ele;Object.keys(r).forEach(s=>{let i=t.getAttribute(s);-1===o.indexOf(s)||""!==i&&"true"!==i||(i=!0),i&&(e[r[s]]=i)})}setEleProps(){const{$ele:e}=this;e.virtualSelect=this,e.value=this.multiple?[]:"",e.name=this.name,e.disabled=!1,e.required=this.required,s.toggleAria(this.$allWrappers,"required",this.required),e.autofocus=this.autofocus,e.multiple=this.multiple,e.form=e.closest("form"),e.reset=l.reset,e.setValue=l.setValueMethod,e.setOptions=l.setOptionsMethod,e.setDisabledOptions=l.setDisabledOptionsMethod,e.setEnabledOptions=l.setEnabledOptionsMethod,e.toggleSelectAll=l.toggleSelectAll,e.isAllSelected=l.isAllSelected,e.addOption=l.addOptionMethod,e.getNewValue=l.getNewValueMethod,e.getDisplayValue=l.getDisplayValueMethod,e.getSelectedOptions=l.getSelectedOptionsMethod,e.getDisabledOptions=l.getDisabledOptionsMethod,e.open=l.openMethod,e.close=l.closeMethod,e.focus=l.focusMethod,e.enable=l.enableMethod,e.disable=l.disableMethod,e.destroy=l.destroyMethod,e.validate=l.validateMethod,e.toggleRequired=l.toggleRequiredMethod,this.hasDropboxWrapper&&(this.$dropboxWrapper.virtualSelect=this)}setValueMethod(e,s){const i=Object.create(null),o=Object.create(null);let n=[];const r=this.multiple;let a=t.normalizeValues(e);if(a){if(Array.isArray(a)||(a=[a]),r){const{maxValues:e}=this;e&&a.length>e&&a.splice(e)}else a.length>1&&(a=[a[0]]);this.useGroupValue&&(a=this.setGroupOptionsValue(a)),a.forEach((e,t)=>{i[e]=!0,o[e]=t}),this.allowNewOption&&a&&this.setNewOptionsFromValue(a)}this.options.forEach(e=>{const s=t.normalizeValues(e.value);!0!==i[s]||e.isDisabled||e.isGroupTitle?e.isSelected=!1:(e.isSelected=!0,n.push(e.value))}),r?(this.hasOptionGroup&&this.setGroupsSelectedProp(),n.sort((e,s)=>o[t.normalizeValues(e)]-o[t.normalizeValues(s)])):[n]=n,this.beforeValueSet(),this.setValue(n,{disableEvent:s}),this.afterValueSet()}setGroupOptionsValue(e){const t=[],s={},i=Object.create(null);return e.forEach(e=>{i[e]=!0}),this.options.forEach(e=>{const{value:o}=e,n=!0===i[o];e.isGroupTitle?n&&(s[e.index]=!0):(n||s[e.groupIndex])&&t.push(o)}),t}setGroupsSelectedProp(){const e=this.isAllGroupOptionsSelected.bind(this);this.options.forEach(t=>{t.isGroupTitle&&(t.isSelected=e(t.index))})}setOptionsMethod(e,t){this.setOptions(e),this.afterSetOptions(t)}setDisabledOptionsMethod(e,t=!1){this.setDisabledOptions(e,!0),t||(this.setValueMethod(null),this.toggleAllOptionsClass()),this.setVisibleOptions()}setDisabledOptions(e,t=!1){let s=[];if(e)if(!0===e)t&&this.options.forEach(e=>(e.isDisabled=!0,s.push(e.value),e));else{s=e.map(e=>e.toString());const i=Object.create(null);s.forEach(e=>{i[e]=!0}),t&&this.options.forEach(e=>(e.isDisabled=!0===i[e.value],e))}else t&&this.options.forEach(e=>(e.isDisabled=!1,e));this.disabledOptions=s}setEnabledOptionsMethod(e,t=!1){this.setEnabledOptions(e),t||(this.setValueMethod(null),this.toggleAllOptionsClass()),this.setVisibleOptions()}setEnabledOptions(e){if(void 0===e)return;const t=[];if(!0===e)this.options.forEach(e=>(e.isDisabled=!1,e));else{const s=Object.create(null);e.forEach(e=>{s[e]=!0}),this.options.forEach(e=>{const i=!0!==s[e.value];return e.isDisabled=i,i&&t.push(e.value),e})}this.disabledOptions=t}setOptions(e=[]){const s=[],i=this.disabledOptions.length,{valueKey:o,labelKey:n,descriptionKey:r,aliasKey:a,hasOptionDescription:l}=this,{getString:h,convertToBoolean:p}=t,c=this.secureText.bind(this),u=this.getAlias.bind(this);let d=0,v=!1;const b=Object.create(null);let m=!1;this.disabledOptions.forEach(e=>{b[e]=!0});const g=e=>{"object"!=typeof e&&(e={[o]:e,[n]:e});const f=h(e[o]),x=h(e[n]),S=f,O=c(x),y=e.options,$=!!y,w={index:d,value:S,valueNormalized:S.toLowerCase(),label:O,labelNormalized:this.searchNormalize&&""!==x.trim()?t.normalizeString(x).toLowerCase():x.toLowerCase(),alias:u(e[a]),isVisible:p(e.isVisible,!0),isNew:e.isNew||!1,isGroupTitle:$,classNames:e.classNames};if(m||""!==S||(m=!0),i&&(w.isDisabled=!0===b[S]),e.isGroupOption&&(w.isGroupOption=!0,w.groupIndex=e.groupIndex),l){const s=h(e[r]);w.description=c(s),w.descriptionNormalized=this.searchNormalize&&""!==s.trim()?t.normalizeString(s).toLowerCase():s.toLowerCase()}if(e.customData&&(w.customData=e.customData),s.push(w),d+=1,$){const e=w.index;v=!0,y.forEach(t=>{t.isGroupOption=!0,t.groupIndex=e,g(t)})}};Array.isArray(e)&&e.forEach(g);const f=s.length,{$ele:x}=this;x.options=s,x.length=f,this.options=s,this.visibleOptionsCount=f,this.lastOptionIndex=f-1,this.newValues=[],this.hasOptionGroup=v,this.hasEmptyValueOption=m,this.setSortedOptions()}setServerOptions(e=[]){this.setOptionsMethod(e,!0);const{selectedOptions:t}=this,i=this.options;let o=!1;if(t.length){const e=Object.create(null);o=!0,i.forEach(t=>{e[t.value]=!0}),t.forEach(t=>{!0!==e[t.value]&&(t.isVisible=!1,i.push(t))}),this.setOptionsMethod(i,!0)}this.allowNewOption&&this.searchValue&&(i.some(e=>e.label.toLowerCase()===this.searchValue)||(o=!0,this.setNewOption())),o?(this.setVisibleOptionsCount(),this.multiple&&this.toggleAllOptionsClass(),this.setValueText()):this.updatePosition(),this.setVisibleOptionsCount(),s.removeClass(this.$allWrappers,"server-searching"),this.isInitialized&&!this.isSilentServerSearch&&this.isOpened()&&this.announce(this.getResultsCountMessage())}setSelectedOptions(){this.selectedOptions=this.options.filter(e=>e.isSelected)}setSortedOptions(){this.ariaMetadataDirty=!0;let e=[...this.options];this.showSelectedOptionsFirst&&this.selectedValues.length&&(e=this.hasOptionGroup?this.sortOptionsGroup(e):this.sortOptions(e)),this.sortedOptions=e}setVisibleOptions(){let e=[...this.sortedOptions];const t=2*this.optionsCount,s=this.getVisibleStartIndex(),i=this.getNewOption(),o=s+t-1;let n=0;i&&(i.visibleIndex=n,n+=1),e=e.filter(e=>{let t=!1;return e.isVisible&&!e.isCurrentNew&&(t=n>=s&&n<=o,e.visibleIndex=n,n+=1),t}),i&&(e=[i,...e]),this.visibleOptions=e,this.visibleOptionsCount=e.length,this.renderOptions()}setOptionsPosition(e){const t=parseInt((e||this.getVisibleStartIndex())*this.optionHeight,10);this.$options.style.transform=`translate3d(0, ${t}px, 0)`,s.setData(this.$options,"top",t)}setOptionsTooltip(){const e=this.getVisibleOptions(),{hasOptionDescription:t}=this;e.forEach(e=>{const i=this.$dropboxContainer.querySelector(`.vscomp-option[data-index="${e.index}"]`);s.setData(i.querySelector(".vscomp-option-text"),"tooltip",e.label),t&&s.setData(i.querySelector(".vscomp-option-description"),"tooltip",e.description)})}setValue(e,{disableEvent:i=!1,disableValidation:o=!1}={}){const n=t.normalizeValues(e);this.hasEmptyValueOption&&""===n||n?Array.isArray(n)?this.selectedValues=[...n]:this.selectedValues=[n]:this.selectedValues=[];const r=this.getValue();this.$ele.value=r,this.$hiddenInput.value=this.getInputValue(r),this.isMaxValuesSelected=!!(this.maxValues&&this.maxValues<=this.selectedValues.length),this.toggleAllOptionsClass(),this.setValueText();const a=t.isNotEmpty(this.selectedValues);s.toggleClass(this.$allWrappers,"has-value",a),s.toggleClass(this.$allWrappers,"max-value-selected",this.isMaxValuesSelected),s.setAttr(this.$clearButton,"tabindex",a?"0":"-1"),s.setAria(this.$clearButton,"hidden",!1===a);let l=!0;o||(l=this.validate()),this.isInitialized&&l&&this.announce(this.getSelectionMessage()),i||s.dispatchEvent(this.$ele,"change",!0)}setValueText(){const{multiple:e,selectedValues:i,noOfDisplayValues:o,showValueAsTags:n,$valueText:r,selectedLabelRenderer:a}=this,l=[];let h=[];const p=i.length;let c=0;const u=this.isAllSelected&&!this.hasServerSearch&&!this.disableAllOptionsSelectedText&&!n;if(u&&this.hideValueTooltipOnSelectAll)r.innerHTML=`${this.allOptionsSelectedText} (${p})`;else{this.getSelectedOptions({fullDetails:!0,keepSelectionOrder:!0}).some(e=>{if(e.isCurrentNew)return!1;if(c>=o)return!0;let{label:s}=e;if("function"==typeof a&&(s=a(e)),l.push(s),c+=1,n){const i=this.getTooltipAttrText(s,!0,!0);let o="";this.ariaLabelTagClearButtonText&&(o=`aria-label="${t.getAriaLabelText(s)}, ${t.getAriaLabelText(this.ariaLabelTagClearButtonText)}"`);const n=`\n ${s}\n \n \n \n `;h.push(n)}else h.push(s);return!1});const i=p-o;i>0&&h.push(`+ ${i} ${this.moreText}`);const d=l.join(", ");if(""===d)r.innerHTML=this.placeholder;else if(r.innerHTML=d,e){const{maxValues:e}=this;if(this.alwaysShowSelectedOptionsCount||s.hasEllipsis(r)||e||n){let t=`${p}`;if(e&&(t+=` / ${e}`),u)r.innerHTML=`${this.allOptionsSelectedText} (${p})`;else if(n)r.innerHTML=h.join(""),this.$valueTags=r.querySelectorAll(".vscomp-value-tag"),this.setValueTagAttr();else if(!this.alwaysShowSelectedOptionsLabel){const e=1===p?this.optionSelectedText:this.optionsSelectedText;r.innerHTML=`${t} ${e}`}}else h=[]}}let d="";0===p?d=this.placeholder:n||(d=h.join(", ")),n||s.setData(r,"tooltip",d),e&&(n?this.updatePosition():s.setData(r,"tooltipEllipsisOnly",0===p))}setSearchValue(e,t=!1,i=!1){if(e===this.searchValueOriginal&&!i)return;t||(this.$searchInput.value=e);const o=e.replace(/\\/g,"").toLowerCase().trim();this.searchValue=o,this.searchValueOriginal=e,s.toggleClass(this.$allWrappers,"has-search-value",e),s.setAttr(this.$searchClear,"tabindex",""!==e?"0":"-1"),s.setAria(this.$searchClear,"hidden",""===e),this.afterSetSearchValue()}setVisibleOptionsCount(){let e,s=0,i=!1;const{searchGroup:o,showOptionsOnlyOnSearch:n,searchByStartsWith:r}=this;let{searchValue:a}=this;a=this.searchNormalize&&""!==a.trim()?t.normalizeString(a):a;const l=this.isOptionVisible.bind(this);this.hasOptionGroup&&(e=this.getVisibleOptionGroupsMapping(a)),this.options.forEach(t=>{if(t.isCurrentNew)return;let h;n&&!a?(t.isVisible=!1,h={isVisible:!1,hasExactOption:!1}):h=l({data:t,searchValue:a,hasExactOption:i,visibleOptionGroupsMapping:e,searchGroup:o,searchByStartsWith:r}),h.isVisible&&(s+=1),i||(i=h.hasExactOption)}),this.allowNewOption&&(a&&!i?(this.setNewOption(),s+=1):this.removeNewOption()),this.visibleOptionsCount=s,this.filteredOptionsCount=s,this.ariaMetadataDirty=!0,this.afterSetVisibleOptionsCount()}calculateAriaMetadata(){let e=0,t=0;if((this.sortedOptions&&this.sortedOptions.length?this.sortedOptions:this.options).forEach(s=>{if(s.isCurrentNew)s.filteredIndex=void 0;else if(!0===s.isVisible){const i=s.isGroupTitle&&this.multiple&&!this.disableOptionGroupCheckbox;!s.isGroupTitle||i?(t+=1,e+=1,s.filteredIndex=t):s.filteredIndex=void 0}else s.filteredIndex=void 0}),this.allowNewOption){const s=this.getNewOption();s&&!0===s.isVisible?(t+=1,e+=1,s.filteredIndex=t):s&&(s.filteredIndex=void 0)}this.ariaSetSize=e}setOptionProp(e,t,s){this.options[e]&&(this.options[e][t]=s)}setOptionsHeight(){this.$optionsList.style.height=this.optionHeight*this.visibleOptionsCount+"px"}setOptionsContainerHeight(e){let t;e?this.showAsPopup&&(this.optionsCount=this.getOptionsCount(),this.halfOptionsCount=Math.ceil(this.optionsCount/2),t=this.getOptionsHeight(),this.optionsHeight=t):(t=this.optionsHeight,this.keepAlwaysOpen&&(s.setStyle(this.$noOptions,"height",t),s.setStyle(this.$noSearchResults,"height",t))),s.setStyle(this.$optionsContainer,"max-height",t),this.afterSetOptionsContainerHeight(e)}setNewOption(e){const t=e||this.searchValueOriginal.trim();if(!t)return;this.ariaMetadataDirty=!0;const s=this.getNewOption();if(s){const e=s.index;this.setOptionProp(e,"value",t),this.setOptionProp(e,"label",this.secureText(t))}else{const s={value:t,label:t};e?(s.isNew=!0,this.newValues.push(t)):s.isCurrentNew=!0,this.addOption(s)}}setSelectedProp(){const e=Object.create(null);this.selectedValues.forEach(t=>{e[t]=!0}),this.options.forEach(t=>{!0===e[t.value]&&(t.isSelected=!0)})}setNewOptionsFromValue(e){if(!e)return;const t=this.setNewOption.bind(this),s=Object.create(null);this.options.forEach(e=>{s[e.value]=!0}),e.forEach(e=>{e&&!0!==s[e]&&t(e)})}setDropboxWrapperWidth(){if(this.showAsPopup)return;const e=this.dropboxWidth||`${this.$wrapper.offsetWidth}px`;s.setStyle(this.$dropboxContainer,"max-width",e)}setEleStyles(){const{maxWidth:e}=this,t={};e&&(t["max-width"]=e),s.setStyles(this.$ele,t)}setDropboxStyles(){const{dropboxWidth:e}=this,t={},i={"z-index":this.zIndex};e&&(this.showAsPopup?t["max-width"]=e:i.width=e),s.setStyles(this.$dropboxContainer,i),s.setStyles(this.$dropbox,t)}setOptionAttr(){const{$visibleOptions:e}=this,{options:t}=this,i=`${this.optionHeight}px`,{setStyle:o,getData:n,setData:r}=s;e&&e.length&&e.forEach(e=>{const s=t[n(e,"index")];o(e,"height",i),r(e,"value",s.value)})}setValueTagAttr(){const{$valueTags:e}=this;if(!e||!e.length)return;const{getData:t,setData:i}=s,{options:o}=this;e.forEach(e=>{const s=t(e,"index");if(void 0!==s){const t=o[s];i(e,"value",t.value)}})}setScrollTop(){const{selectedValues:e}=this;if(this.showSelectedOptionsFirst||!this.focusSelectedOptionOnOpen||0===e.length)return;const t=Object.create(null);let s;e.forEach(e=>{t[e]=!0}),this.options.some(e=>!!t[e.value]&&(s=e.visibleIndex,!0)),s&&(this.$optionsContainer.scrollTop=this.optionHeight*s)}getVisibleOptions(){return this.visibleOptions||[]}getValue(){let e;return e=this.multiple?this.useGroupValue?this.getGroupValue():this.selectedValues:this.selectedValues[0]||"",t.normalizeValues(e)}getGroupValue(){const e=[],t={};return this.options.forEach(s=>{if(!s.isSelected)return;const{value:i}=s;s.isGroupTitle?i&&(t[s.index]=!0,e.push(i)):!0!==t[s.groupIndex]&&e.push(i)}),e}getInputValue(e){let t=e;return t&&t.length?this.setValueAsArray&&this.multiple&&(t=JSON.stringify(t)):t=this.emptyValue,t}getFirstVisibleOptionIndex(){return Math.ceil(this.$optionsContainer.scrollTop/this.optionHeight)}getVisibleStartIndex(){let e=this.getFirstVisibleOptionIndex()-this.halfOptionsCount;return e<0&&(e=0),e}getTooltipAttrText(e,t=!1,i=!1){const o={"data-tooltip":e||"","data-tooltip-enter-delay":this.tooltipEnterDelay,"data-tooltip-z-index":this.zIndex,"data-tooltip-font-size":this.tooltipFontSize,"data-tooltip-alignment":this.tooltipAlignment,"data-tooltip-max-width":this.tooltipMaxWidth,"data-tooltip-ellipsis-only":t,"data-tooltip-allow-html":i};return s.getAttributesText(o)}getOptionObj(e){if(!e)return;const{getString:s}=t,i=this.secureText.bind(this),o=s(e.value),n=s(e.label),r=s(e.description);return{index:e.index,value:o,valueNormalized:o.toLowerCase(),label:i(n),labelNormalized:this.searchNormalize&&""!==n.trim()?t.normalizeString(n).toLowerCase():n.toLowerCase(),description:i(r),descriptionNormalized:this.searchNormalize&&""!==r.trim()?t.normalizeString(r).toLowerCase():r.toLowerCase(),alias:this.getAlias(e.alias),isCurrentNew:e.isCurrentNew||!1,isNew:e.isNew||!1,isVisible:!0}}getNewOption(){const e=this.options[this.lastOptionIndex];if(e&&e.isCurrentNew)return e}getOptionIndex(e){let t;return this.options.some(s=>s.value===e&&(t=s.index,!0)),t}getNewValue(){const e=Object.create(null);this.newValues.forEach(t=>{e[t]=!0});const t=this.selectedValues.filter(t=>!0===e[t]);return this.multiple?t:t[0]}getAlias(e){let t=e;return t&&(t=Array.isArray(t)?t.join(","):t.toString().trim(),t=t.toLowerCase()),t||""}getDisplayValue(){const e=[];return this.options.forEach(t=>{t.isSelected&&e.push(t.label)}),this.multiple?e:e[0]||""}getSelectedOptions({fullDetails:e=!1,keepSelectionOrder:t=!1}={}){const{valueKey:s,labelKey:i,selectedValues:o}=this,n=[];if(this.options.forEach(t=>{if(t.isSelected&&!t.isGroupTitle)if(e)n.push(t);else{const e={[s]:t.value,[i]:t.label};t.isNew&&(e.isNew=!0),t.customData&&(e.customData=t.customData),n.push(e)}}),t){const e=Object.create(null);o.forEach((t,s)=>{e[t]=s}),n.sort((t,s)=>e[t.value]-e[s.value])}return this.multiple||e?n:n[0]}getDisabledOptions(){const{valueKey:e,labelKey:t,disabledOptions:s}=this,i=Object.create(null),o=[];return s.forEach(e=>{i[e]=!0}),this.options.forEach(({value:s,label:n})=>{i[s]&&o.push({[e]:s,[t]:n})}),o}getVisibleOptionGroupsMapping(e){let{options:t}=this;const s={},i=this.isOptionVisible.bind(this);return t=this.structureOptionGroup(t),t.forEach(t=>{s[t.index]=t.options.some(t=>i({data:t,searchValue:e}).isVisible)}),s}getOptionsCount(e){let t;if(this.showAsPopup){let e=80*window.innerHeight/100-48;this.hasSearchContainer&&(e-=40),t=Math.floor(e/this.optionHeight)}else t=parseInt(e,10);return t}getOptionsHeight(){return this.optionsCount*this.optionHeight+"px"}isSelectableGroupTitle(e){return e&&s.hasClass(e,"group-title")&&this.multiple&&!this.disableOptionGroupCheckbox}shouldSkipOptionInNavigation(e){return!!e&&(!!s.hasClass(e,"disabled")||s.hasClass(e,"group-title")&&!this.isSelectableGroupTitle(e))}getSibling(e,t){const s="next"===t?"nextElementSibling":"previousElementSibling";let i=e;do{i&&(i=i[s])}while(this.shouldSkipOptionInNavigation(i));return i}getUniqueId(){const e=t.getRandomInt(1e4);return document.querySelector(`#vscomp-ele-wrapper-${e}`)?this.getUniqueId():e}initDropboxPopover(){const e={ele:this.$ele,target:this.$dropboxContainer,position:this.position,zIndex:this.zIndex,margin:4,transitionDistance:30,hideArrowIcon:!0,disableManualAction:!0,disableUpdatePosition:!this.hasDropboxWrapper,updatePositionThrottle:this.updatePositionThrottle,showDuration:this.showDuration,hideDuration:this.hideDuration,afterShow:this.afterShowPopper.bind(this),afterHide:this.afterHidePopper.bind(this)};this.dropboxPopover=new PopoverComponent(e)}openDropbox(e){l.lastInteractedInstance=this;let t="";e||(t=this.$dropboxContainer.style.transition,this.$dropboxContainer.style.transition="none"),this.isSilentOpen=e,l.openInstances.forEach(e=>{if(e!==this){const t=e;t.shouldFocusWrapperOnClose=!1,t.closeDropbox(!0)}}),l.openInstances.add(this),this.isSilentServerSearch=!1,s.setAttr(this.$dropboxWrapper,"tabindex","0"),s.setAria(this.$dropboxWrapper,"hidden",!1),s.setAttr(this.$dropboxContainerTop,"tabindex","0"),s.setAria(this.$dropboxContainerTop,"hidden",!1),s.setAttr(this.$dropboxContainerBottom,"tabindex","0"),s.setAria(this.$dropboxContainerBottom,"hidden",!1),e?s.setStyle(this.$dropboxContainer,"display","inline-flex"):(s.dispatchEvent(this.$ele,"beforeOpen"),s.setAria(this.$wrapper,"expanded",!0)),this.setDropboxWrapperWidth(),s.removeClass(this.$allWrappers,"closed"),s.changeTabIndex(this.$allWrappers,0),e||(this.$dropboxContainer.offsetHeight,this.$dropboxContainer.style.transition=t),this.dropboxPopover&&!e?this.dropboxPopover.show():this.afterShowPopper()}afterShowPopper(){const e=this.isSilentOpen;this.isSilentOpen=!1,e||(this.moveSelectedOptionsFirst(),this.setScrollTop(),s.addClass(this.$allWrappers,"focused"),this.showAsPopup?(s.addClass(this.$body,"vscomp-popup-active"),this.isPopupActive=!0):this.focusElementOnOpen(),s.dispatchEvent(this.$ele,"afterOpen"))}closeDropbox(e){if(this.isSilentClose=e,l.openInstances.delete(this),!1===this.isOpened())return;if(this.keepAlwaysOpen)return void this.removeOptionFocus();const t=document.activeElement,i=t&&this.$wrapper.contains(t)||this.hasDropboxWrapper&&t&&this.$dropboxWrapper.contains(t);this.shouldFocusWrapperOnClose&&l.lastInteractedInstance===this&&!e&&(null===t||t===document.body||i)&&this.$wrapper.focus(),e?s.setStyle(this.$dropboxContainer,"display",""):(s.dispatchEvent(this.$ele,"beforeClose"),s.setAria(this.$wrapper,"expanded",!1),this.removeOptionFocus(),this.setActiveDescendant("")),this.dropboxPopover&&!e?(this.dropboxPopover.hide(),s.setAttr(this.$dropboxWrapper,"tabindex","-1"),s.setAria(this.$dropboxWrapper,"hidden",!0),s.setAttr(this.$dropboxContainerTop,"tabindex","-1"),s.setAria(this.$dropboxContainerTop,"hidden",!0),s.setAttr(this.$dropboxContainerBottom,"tabindex","-1"),s.setAria(this.$dropboxContainerBottom,"hidden",!0)):this.afterHidePopper(),this.isClosing=!0;try{this.setSearchValue("")}finally{this.isClosing=!1}this.hasServerSearch&&(this.isSilentServerSearch=!0)}afterHidePopper(){const e=this.isSilentClose;this.isSilentClose=!1,s.removeClass(this.$allWrappers,"focused"),this.removeOptionFocus(),!e&&this.isPopupActive&&(s.removeClass(this.$body,"vscomp-popup-active"),this.isPopupActive=!1),s.addClass(this.$allWrappers,"closed"),e||s.dispatchEvent(this.$ele,"afterClose"),this.shouldFocusWrapperOnClose=!0,s.setAttr(this.$dropboxWrapper,"tabindex","-1"),s.setAria(this.$dropboxWrapper,"hidden",!0),s.setAttr(this.$dropboxContainerTop,"tabindex","-1"),s.setAria(this.$dropboxContainerTop,"hidden",!0),s.setAttr(this.$dropboxContainerBottom,"tabindex","-1"),s.setAria(this.$dropboxContainerBottom,"hidden",!0)}moveSelectedOptionsFirst(){this.$optionsContainer.scrollTop&&this.selectedValues.length||this.setVisibleOptions(),this.showSelectedOptionsFirst&&(this.setSortedOptions(),this.scrollToTop(),this.setVisibleOptions())}toggleDropbox(){l.lastInteractedInstance=this,this.isOpened()?this.closeDropbox():this.openDropbox()}updatePosition(){this.dropboxPopover&&this.isOpened()&&this.$ele.updatePosition()}isOpened(){return!s.hasClass(this.$wrapper,"closed")}focusSearchInput(){const e=this.$searchInput;e&&e.focus()}focusElementOnOpen(){const e=this.$searchInput,t=!this.options.length&&!this.hasServerSearch;if(e)t&&!this.allowNewOption?(s.setAttr(e,"disabled",""),this.$noOptions.focus()):(e.removeAttribute("disabled"),e.focus());else{const e=this.$dropbox.querySelector('[tabindex="0"]');void 0!==s.getData(e,"index")?this.focusOption({direction:"next"}):e?e.focus():this.focusFirstVisibleOption()}}focusFirstVisibleOption(){let e=this.$optionsContainer.querySelector(`[data-index='${this.getFirstVisibleOptionIndex()}']`);e?(this.shouldSkipOptionInNavigation(e)&&(e=this.getSibling(e,"next")),e&&(s.setAttr(e,"tabindex","0"),this.$optionsContainer.scrollTop=this.optionHeight*this.getFirstVisibleOptionIndex(),this.focusOption({focusFirst:!0}),e.focus())):(e=this.$dropbox.querySelector('[tabindex="0"]'),e&&e.focus())}focusOption({direction:e,$option:t,focusFirst:i}={}){const o=this.$dropboxContainer.querySelector(".vscomp-option.focused");let n;if(t)n=t;else if(!o||i){const e=this.getFirstVisibleOptionIndex();n=this.$dropboxContainer.querySelector(`.vscomp-option[data-visible-index="${e}"]`),this.shouldSkipOptionInNavigation(n)&&(n=this.getSibling(n,"next"))}else n=this.getSibling(o,e);n&&n!==o&&(o&&this.toggleOptionFocusedState(o,!1),this.toggleOptionFocusedState(n,!0),this.toggleFocusedProp(s.getData(n,"index"),!0),this.moveFocusedOptionToView(n))}moveFocusedOptionToView(e){const t=e||this.$dropboxContainer.querySelector(".vscomp-option.focused");if(!t)return;let i;const o=this.$optionsContainer.getBoundingClientRect(),n=t.getBoundingClientRect(),r=o.top,a=o.bottom,l=o.height,h=n.top,p=n.bottom,c=n.height,u=t.offsetTop,d=s.getData(this.$options,"top","number");r>h?i=u+d:a{if(e.isDisabled||e.isGroupTitle||!e.isVisible||e.isSelected)return;const{index:t}=e;if(t>o&&t{e(parseInt(t,10))})}this.setManagedTimeout(()=>{this.renderOptions()},0)}toggleAllOptions(e){if(!this.multiple||this.disableSelectAll)return;const t="boolean"==typeof isSelected?e:!s.hasClass(this.$toggleAllCheckbox,"checked"),i=[],{selectAllOnlyVisible:o}=this;this.options.forEach(e=>{const s=e;if(s.isDisabled||s.isCurrentNew)return;const{isVisible:n,isSelected:r}=s;!t&&(!o||n||!r)||t&&o&&!n&&!r?s.isSelected=!1:(s.isSelected=!0,s.isGroupTitle||i.push(s.value))}),this.toggleAllOptionsClass(t),this.setValue(i),this.renderOptions()}toggleAllOptionsClass(e){if(!this.multiple)return;let t=!1;"boolean"==typeof e||(e=this.isAllOptionsSelected()),!e&&this.selectAllOnlyVisible&&""!==this.searchValue&&(this.visibleOptionsCount>0||""===this.searchValue)&&(t=this.isAllOptionsSelected(!0));const i=e||t;s.toggleClass(this.$toggleAllCheckbox,"checked",i),s.setAria(this.$toggleAllButton,"checked",i),this.isAllSelected=e}isAllOptionsSelected(e){let t=!1;return this.options.length&&this.selectedValues.length&&(t=!this.options.some(t=>!t.isSelected&&!t.isDisabled&&!t.isGroupTitle&&(!e||t.isVisible))),t}isAllGroupOptionsSelected(e){let t=!1;return this.options.length&&(t=!this.options.some(t=>!t.isSelected&&!t.isDisabled&&!t.isGroupTitle&&t.groupIndex===e)),t}toggleGroupOptionsParent(e,t){if(!this.hasOptionGroup||this.disableOptionGroupCheckbox||!e)return;let i=s.getData(e,"groupIndex");void 0!==i&&(i=parseInt(i,10));const o=this.$options.querySelector(`.vscomp-option[data-index="${i}"]`),n="boolean"==typeof t?t:this.isAllGroupOptionsSelected(i);this.toggleGroupTitleCheckbox(o,n),this.toggleGroupTitleProp(i,n)}toggleGroupTitleProp(e,t){const s="boolean"==typeof t?t:this.isAllGroupOptionsSelected(e);this.toggleSelectedProp(e,s)}toggleGroupOptions(e,i){if(!this.hasOptionGroup||this.disableOptionGroupCheckbox||!e)return;const o=s.getData(e,"index","number"),{selectedValues:n,selectAllOnlyVisible:r}=this,a=Object.create(null),{removeItemFromArray:l}=t;n.forEach(e=>{a[e]=!0}),this.options.forEach(e=>{if(e.isDisabled||e.groupIndex!==o)return;const{value:t}=e;!i||r&&!e.isVisible?(e.isSelected=!1,a[t]&&l(n,t)):(e.isSelected=!0,a[t]||n.push(t))}),this.toggleAllOptionsClass(!!i&&null),this.setValue(n),this.setManagedTimeout(()=>{this.renderOptions()},0)}toggleGroupTitleCheckbox(e,t){if(!e)return;const i=s.getData(e,"index","number");this.toggleSelectedProp(i,t),this.toggleOptionSelectedState(e,t)}toggleFocusedProp(e,t=!1){null!==this.focusedOptionIndex&&void 0!==this.focusedOptionIndex&&this.setOptionProp(this.focusedOptionIndex,"isFocused",!1),this.setOptionProp(e,"isFocused",t),this.focusedOptionIndex=e}toggleSelectedProp(e,t=!1){this.setOptionProp(e,"isSelected",t)}scrollToTop(){const{scrollTop:e}=this.$optionsContainer;e>0&&(this.$optionsContainer.scrollTop=0)}reset(e=!1,t=!1){this.options.forEach(e=>{e.isSelected=!1}),this.beforeValueSet(!0),this.setValue(null,{disableEvent:t,disableValidation:e}),this.afterValueSet(),e&&(s.removeClass(this.$allWrappers,"has-error"),s.toggleAria(this.$allWrappers,"invalid",!1),this.setErrorMessage("")),s.dispatchEvent(this.$ele,"reset")}addOption(e,t){if(!e)return;this.lastOptionIndex+=1;const s=this.getOptionObj({...e,index:this.lastOptionIndex});this.options.push(s),this.sortedOptions.push(s),t&&(this.visibleOptionsCount+=1,this.afterSetOptions())}removeOption(e){(e||0===e)&&(this.options.splice(e,1),this.lastOptionIndex-=1)}removeNewOption(){const e=this.getNewOption();e&&(this.ariaMetadataDirty=!0,this.removeOption(e.index))}sortOptions(e){return e.sort((e,t)=>{const s=e.isSelected||e.isAnySelected,i=t.isSelected||t.isAnySelected;return s||i?s&&(!i||e.index{const s=e.options;e.isAnySelected=s.some(e=>e.isSelected),e.isAnySelected&&t(s)}),t(s),this.destructureOptionGroup(s)}isOptionVisible({data:e,searchValue:s,hasExactOption:i,visibleOptionGroupsMapping:o,searchGroup:n,searchByStartsWith:r}){const a=null!=e.valueNormalized?e.valueNormalized:e.value.toLowerCase();let l=e.labelNormalized;if(null==l){const s=(e.label||"").trim();l=this.searchNormalize&&""!==s?t.normalizeString(s).toLowerCase():s.toLowerCase()}const{description:h,alias:p}=e;let{descriptionNormalized:c}=e;if(null==c){const e=h||"";c=this.searchNormalize&&""!==e.trim()?t.normalizeString(e).toLowerCase():e.toLowerCase()}let u=r?l.startsWith(s):l.includes(s);return!e.isGroupTitle||n&&u||(u=o[e.index]),r||!p||u||(u=p.includes(s)),r||!c||u||(u=c.includes(s)),e.isVisible=u,i||(i=l===s||a===s),{isVisible:u,hasExactOption:i}}structureOptionGroup(e){const t=[],s={};return e.forEach(e=>{if(e.isGroupTitle){const i=[];e.options=i,s[e.index]=i,t.push(e)}}),e.forEach(e=>{e.isGroupOption&&s[e.groupIndex].push(e)}),t}destructureOptionGroup(e){let t=[];return e.forEach(e=>{t.push(e),t=t.concat(e.options)}),t}serverSearch(){s.removeClass(this.$allWrappers,"has-no-search-results"),s.addClass(this.$allWrappers,"server-searching"),this.isInitialized&&!this.isSilentServerSearch&&this.isOpened()&&this.announce(this.loadingText),this.setSelectedOptions(),this.onServerSearch(this.searchValue,this)}removeValue(e){const{selectedValues:i}=this,o=s.getData(e,"value");t.removeItemFromArray(i,o),this.setValueMethod(i)}focus(){this.$wrapper.focus()}enable(){this.$ele.disabled=!1,this.$ele.removeAttribute("disabled"),this.$hiddenInput.removeAttribute("disabled"),s.setAria(this.$wrapper,"disabled",!1),s.changeTabIndex(this.$wrapper,0)}disable(){this.$ele.disabled=!0,this.$ele.setAttribute("disabled",""),this.$hiddenInput.setAttribute("disabled",""),s.setAria(this.$wrapper,"disabled",!0),s.changeTabIndex(this.$wrapper,-1),this.$wrapper.blur()}validate(){if(this.disableValidation)return!0;let e=!1,i="";const{selectedValues:o,minValues:n}=this;return this.required&&(t.isEmpty(o)?(e=!0,i=this.requiredErrorText):this.multiple&&n&&o.length{this.managedTimeouts.delete(s),e()},t);return this.managedTimeouts.add(s),s}clearManagedTimeouts(){this.managedTimeouts&&(this.managedTimeouts.forEach(e=>clearTimeout(e)),this.managedTimeouts.clear())}destroy(){if(this.isDestroyed)return;this.isDestroyed=!0;const{$ele:e}=this;e.virtualSelect=void 0,e.value=void 0,e.innerHTML="",l.openInstances.delete(this),this===l.lastInteractedInstance&&(l.lastInteractedInstance=null),this.serverSearchTimeout&&(clearTimeout(this.serverSearchTimeout),this.serverSearchTimeout=null),this.clearManagedTimeouts(),this.scrollAnimationFrame&&(cancelAnimationFrame(this.scrollAnimationFrame),this.scrollAnimationFrame=null),this.removeEvents(),this.hasDropboxWrapper&&(this.$dropboxWrapper.virtualSelect=void 0,this.$dropboxWrapper.remove()),this.dropboxPopover&&this.dropboxPopover.destroy(),s.removeClass(e,"vscomp-ele"),this.events={},l.unregisterInstance(this)}createSecureTextElements(){this.$secureDiv=document.createElement("div"),this.$secureText=document.createTextNode(""),this.$secureDiv.appendChild(this.$secureText)}secureText(e){return e&&this.enableSecureText?(this.$secureText.nodeValue=e,this.$secureDiv.innerHTML):e}warnIfSecureTextDisabled(){l.secureTextWarningShown||this.enableSecureText||!this.showSecureTextWarning||(l.secureTextWarningShown=!0,console.warn("[virtual-select] Option text (label, value, description) and any `customData` used in markup are rendered as HTML and are NOT escaped because `enableSecureText` is disabled (the default, kept off for performance on large datasets). If any option text can come from untrusted input, set `enableSecureText: true` to prevent XSS. Docs: https://sa-si-dev.github.io/virtual-select/#/properties"))}announce(e){if(!this.$liveRegion)return;const s=t.getPlainText(e||"");this.$liveRegion.textContent!==s&&(this.$liveRegion.textContent=s)}getResultsCountMessage(){const e=this.filteredOptionsCount||0;return 0===e?this.noSearchResultsText:`${e} ${1===e?this.searchResultText:this.searchResultsText}`}getSelectionMessage(){const e=this.selectedValues.length;return 0===e?this.noOptionsSelectedText:this.multiple?`${e} ${1===e?this.optionSelectedText:this.optionsSelectedText}`:`${this.getDisplayValue()||this.selectedValues[0]} ${this.selectedText}`}announceSearchResults(){this.isInitialized&&this.isOpened()&&document.activeElement===this.$searchInput&&this.announce(this.getResultsCountMessage())}toggleRequired(e){this.required=t.convertToBoolean(e),this.$ele.required=this.required,s.toggleAria(this.$allWrappers,"required",this.required),this.required||(s.toggleClass(this.$allWrappers,"has-error",!1),s.toggleAria(this.$allWrappers,"invalid",!1),this.setErrorMessage(""))}toggleOptionSelectedState(e,t){let i=t;void 0===i&&(i=!s.hasClass(e,"selected")),s.toggleClass(e,"selected",i),s.setAria(e,"selected",i)}toggleOptionFocusedState(e,t){e&&(s.toggleClass(e,"focused",t),s.setAttr(e,"tabindex",t?"0":"-1"),t&&document.activeElement!==this.$searchInput&&e.focus(),this.setActiveDescendant(t?e.id:""))}setActiveDescendant(e){s.toggleAria(this.$wrapper,"activedescendant",!!e,e),s.toggleAria(this.$searchInput,"activedescendant",!!e,e)}static setGlobalDefaults(e){if(!e||"object"!=typeof e)return;const t={...e};delete t.ele,delete t.options,l.globalDefaults={...l.globalDefaults,...t}}static resetGlobalDefaults(){l.globalDefaults={}}static getGlobalDefaults(){return{...l.globalDefaults}}static init(e){let t=e.ele;if(!t)return;let s=!1;if("string"==typeof t){t=document.querySelectorAll(t);const e=t.length;if(0===e)return;1===e&&(s=!0)}void 0!==t.length&&void 0!==t.forEach||(t=[t],s=!0);const i=[];return t.forEach(t=>{t.virtualSelect?i.push(t.virtualSelect):(e.ele=t,"SELECT"===t.tagName&&l.setPropsFromSelect(e),i.push(new l(e)))}),s?i[0]:i}static getAttrProps(){const{convertPropToDataAttr:e}=s,t={};return n.forEach(e=>{t[e]=e}),a.forEach(s=>{t[e(s)]=s}),t}static setPropsFromSelect(e){const t=e.ele,i=[],n=[],a=e=>{const t=[];return Array.from(e.children).forEach(e=>{const{value:s}=e,o={value:s};"OPTGROUP"===e.tagName?(o.label=e.getAttribute("label"),o.options=a(e)):o.label=e.innerHTML,t.push(o),e.disabled&&i.push(s),e.selected&&n.push(s)}),t},l=a(t),h=document.createElement("div");s.setAttrFromEle(t,h,Object.keys(r),o),t.parentNode.insertBefore(h,t),t.remove(),e.ele=h,e.options=l,e.disabledOptions=i,e.selectedValue=n}static onFormReset(e){const t=e.target.closest("form");t&&t.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{e.parentElement.virtualSelect.reset(!0)})}static onFormSubmit(e){l.validate(e.target.closest("form"))||e.preventDefault()}static validate(e){if(!e)return!0;let t=!1;return e.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{const s=e.parentElement.virtualSelect.validate();t||s||(t=!0)}),!t}static reset(e=!1,t=!1){this.virtualSelect.reset(e,t)}static setValueMethod(...e){this.virtualSelect.setValueMethod(...e)}static setOptionsMethod(...e){this.virtualSelect.setOptionsMethod(...e)}static setDisabledOptionsMethod(...e){this.virtualSelect.setDisabledOptionsMethod(...e)}static setEnabledOptionsMethod(...e){this.virtualSelect.setEnabledOptionsMethod(...e)}static toggleSelectAll(e){this.virtualSelect.toggleAllOptions(e)}static isAllSelected(){return this.virtualSelect.isAllSelected}static addOptionMethod(e){this.virtualSelect.addOption(e,!0)}static getNewValueMethod(){return this.virtualSelect.getNewValue()}static getDisplayValueMethod(){return this.virtualSelect.getDisplayValue()}static getSelectedOptionsMethod(e){return this.virtualSelect.getSelectedOptions(e)}static getDisabledOptionsMethod(){return this.virtualSelect.getDisabledOptions()}static openMethod(){return this.virtualSelect.openDropbox()}static closeMethod(){return this.virtualSelect.closeDropbox()}static focusMethod(){return this.virtualSelect.focus()}static enableMethod(){return this.virtualSelect.enable()}static disableMethod(){return this.virtualSelect.disable()}static destroyMethod(){return this.virtualSelect.destroy()}static validateMethod(){return this.virtualSelect.validate()}static toggleRequiredMethod(e){return this.virtualSelect.toggleRequired(e)}static onResizeMethod(){document.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{const t=e.parentElement&&e.parentElement.virtualSelect;t&&t.onResize()})}}l.onResizeThrottled=t.throttle(l.onResizeMethod,100),r=l.getAttrProps(),window.VirtualSelect=l,l.openInstances=new Set,l.domObserver=null,l.activeInstances=new Set,l.hasGlobalListeners=!1,l.lastInteractedInstance=null,l.secureTextWarningShown=!1,l.globalDefaults={},"undefined"!=typeof NodeList&&NodeList.prototype&&!NodeList.prototype.forEach&&(NodeList.prototype.forEach=Array.prototype.forEach)}(),function(){"use strict";function e(e){return function(e){if(Array.isArray(e))return t(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,s){if(e){if("string"==typeof e)return t(e,s);var i=Object.prototype.toString.call(e).slice(8,-1);return"Object"===i&&e.constructor&&(i=e.constructor.name),"Map"===i||"Set"===i?Array.from(e):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?t(e,s):void 0}}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function t(e,t){(null==t||t>e.length)&&(t=e.length);for(var s=0,i=new Array(t);ss-o-t.width?"left":"right",vertical:n>i-n-t.height?"top":"bottom"}}},{key:"getAbsoluteCoords",value:function(e){if(e){var t=e.getBoundingClientRect(),s=window.pageXOffset,i=window.pageYOffset;return{width:t.width,height:t.height,top:t.top+i,right:t.right+s,bottom:t.bottom+i,left:t.left+s}}}},{key:"getCoords",value:function(e){return e?e.getBoundingClientRect():{}}},{key:"getData",value:function(e,t,s){if(e){var i=e?e.dataset[t]:"";return"number"===s?i=parseFloat(i)||0:"true"===i?i=!0:"false"===i&&(i=!1),i}}},{key:"setData",value:function(e,t,s){e&&(e.dataset[t]=s)}},{key:"setStyle",value:function(e,t,s){e&&(e.style[t]=s)}},{key:"show",value:function(e){var s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"block";t.setStyle(e,"display",s)}},{key:"hide",value:function(e){t.setStyle(e,"display","none")}},{key:"getHideableParent",value:function(e){for(var t,s=e.parentElement;s;){var i=getComputedStyle(s).overflow;if(-1!==i.indexOf("scroll")||-1!==i.indexOf("auto")){t=s;break}s=s.parentElement}return t}}],s&&function(e,t){for(var s=0;sx?x-b:M:w+p>L&&("right"===T?n="left":w=L+bS?S-u:P:C+c>I&&("bottom"===T?n="top":C=I+up-j&&(G=p-j):"left"!==T&&"right"!==T||((R=g/2+f-H)c-j&&(R=c-j)),s.setStyle(this.$arrowEle,"transform","translate3d(".concat(parseInt(G),"px, ").concat(parseInt(R),"px, 0) ").concat(K))}s.hide(this.$popperEle)}},{key:"resetPosition",value:function(){s.setStyle(this.$popperEle,"transform","none"),this.setPosition()}},{key:"show",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},i=t.resetPosition,o=t.data;clearTimeout(this.exitDelayTimeout),clearTimeout(this.hideDurationTimeout),i&&this.resetPosition(),this.enterDelayTimeout=setTimeout(function(){var t=s.getData(e.$popperEle,"left"),i=s.getData(e.$popperEle,"top"),n="translate3d(".concat(parseInt(t),"px, ").concat(parseInt(i),"px, 0)"),r=e.showDuration;s.show(e.$popperEle,"inline-flex"),s.getCoords(e.$popperEle),s.setStyle(e.$popperEle,"transitionDuration",r+"ms"),s.setStyle(e.$popperEle,"transform",n),s.setStyle(e.$popperEle,"opacity",1),e.showDurationTimeout=setTimeout(function(){"function"==typeof e.afterShowCallback&&e.afterShowCallback(o)},r)},this.enterDelay)}},{key:"hide",value:function(){var e=this,t=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).data;clearTimeout(this.enterDelayTimeout),clearTimeout(this.showDurationTimeout),this.exitDelayTimeout=setTimeout(function(){if(e.$popperEle){var i=parseInt(s.getData(e.$popperEle,"fromLeft")),o=parseInt(s.getData(e.$popperEle,"fromTop")),n="translate3d(".concat(i,"px, ").concat(o,"px, 0)"),r=e.hideDuration;s.setStyle(e.$popperEle,"transitionDuration",r+"ms"),s.setStyle(e.$popperEle,"transform",n),s.setStyle(e.$popperEle,"opacity",0),e.hideDurationTimeout=setTimeout(function(){s.hide(e.$popperEle),"function"==typeof e.afterHideCallback&&e.afterHideCallback(t)},r)}},this.exitDelay)}},{key:"updatePosition",value:function(){s.setStyle(this.$popperEle,"transitionDuration","0ms"),this.resetPosition();var e=parseInt(s.getData(this.$popperEle,"left")),t=parseInt(s.getData(this.$popperEle,"top"));s.show(this.$popperEle,"inline-flex"),s.setStyle(this.$popperEle,"transform","translate3d(".concat(e,"px, ").concat(t,"px, 0)"))}}],t&&function(e,t){for(var s=0;s1&&void 0!==arguments[1]&&arguments[1]}},{key:"removeArrayEmpty",value:function(e){return Array.isArray(e)&&e.length?e.filter(function(e){return!!e}):[]}},{key:"throttle",value:function(e,t){var s,i=0;return function(){for(var o=arguments.length,n=new Array(o),r=0;re.length)&&(t=e.length);for(var s=0,i=new Array(t);s'),e=this.$popover.querySelector(".pop-comp-arrow")),this.$arrowEle=e}}},{key:"destroy",value:function(){this.removeEvents()}}])&&c(t.prototype,s),o&&c(t,o),Object.defineProperty(t,"prototype",{writable:!1}),t;var t,s,o}();d=m.getAttrProps(),window.PopoverComponent=m}(); \ No newline at end of file diff --git a/docs/assets/virtual-select.js b/docs/assets/virtual-select.js index 42bceea..9e289f2 100644 --- a/docs/assets/virtual-select.js +++ b/docs/assets/virtual-select.js @@ -1,5 +1,5 @@ /*! - * Virtual Select v1.3.0 + * Virtual Select v1.4.0 * https://sa-si-dev.github.io/virtual-select * Licensed under MIT (https://github.com/sa-si-dev/virtual-select/blob/master/LICENSE) *//******/ (function() { // webpackBootstrap @@ -191,24 +191,16 @@ class Utils { } /** + * Whether the user has asked the operating system to reduce motion. + * + * Read on each call rather than cached, so a preference changed after page load is picked up + * by the next instance. Guarded for environments without matchMedia. + * * @static - * @param {*} container - * @param {string} text - * @return {boolean} - * @memberof Utils + * @returns {boolean} */ - static willTextOverflow(container, text) { - const tempElement = document.createElement('div'); - tempElement.style.position = 'absolute'; - tempElement.style.visibility = 'hidden'; - tempElement.style.whiteSpace = 'nowrap'; - tempElement.style.fontSize = window.getComputedStyle(container).fontSize; - tempElement.style.fontFamily = window.getComputedStyle(container).fontFamily; - tempElement.textContent = text; - document.body.appendChild(tempElement); - const textWidth = tempElement.clientWidth; - document.body.removeChild(tempElement); - return textWidth > container.clientWidth; + static prefersReducedMotion() { + return typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches; } /** @@ -221,6 +213,83 @@ class Utils { return text.replace(/"/g, '"'); } + /** + * Escape a *raw* string for interpolation into a double-quoted HTML attribute. + * + * Use this only where the input has not already been HTML-escaped - currently the option + * value, which is stored verbatim because it reaches no innerHTML sink. `&` must be escaped + * first, otherwise the `&` introduced by the quote replacement would itself be escaped and + * the attribute would parse back as a literal `"`. + * + * Deliberately NOT used by DomUtils.getAttributesText(), whose inputs are already-escaped + * label text: escaping `&` there would double it and a tooltip would show `&`. That + * asymmetry is the reason this is a separate helper rather than a shared one. + * + * @static + * @param {string} text + * @return {string} + * @memberof Utils + */ + static escapeAttributeValue(text) { + return Utils.getString(text).replace(/&/g, '&').replace(/"/g, '"'); + } + + /** + * Undo the escaping secureText() applies, recovering the text a human should read. + * + * Option label and description are stored HTML-escaped when enableSecureText is on, because + * they are inserted as HTML. Anywhere that text is consumed as *text* instead - an accessible + * name, a live-region announcement - the escape sequences have to come back off, or the user + * is read `&` and `<i class=...`. + * + * `&` is decoded last: doing it first would turn a literal `&lt;` into `<` and then + * into `<`, inventing markup the consumer never wrote. + * + * @static + * @param {string} text + * @return {string} + * @memberof Utils + */ + static decodeSecureText(text) { + return Utils.getString(text).replace(/</g, '<').replace(/>/g, '>').replace(/ /g, '\u00A0').replace(/&/g, '&'); + } + + /** + * Reduce label text to the words a human should hear or read. + * + * Labels may legitimately contain markup - an icon, , a
. Wherever that text is + * consumed as text (an accessible name, a live-region announcement) the markup is meaningless + * and is read out as tag soup. Tags collapse to a single space so adjacent words do not run + * together, so "France
Paris" does not become one word. + * + * The escaping is undone first. With enableSecureText on the label arrives already escaped, so + * the tag pattern found no `<` to match and the markup passed through verbatim - the strip was + * a no-op in exactly the mode escaping is enabled in. + * + * @static + * @param {string} text + * @return {string} + * @memberof Utils + */ + static getPlainText(text) { + return Utils.decodeSecureText(text).replace(/<[^>]+>/gi, ' ').replace(/\s+/g, ' ').trim(); + } + + /** + * Turn a label into text that is safe and sensible inside an aria-label attribute. + * + * Plain text, then escaped for the attribute - covering `&` as well as `"`, so a bare + * ampersand in a label is a valid character reference rather than raw markup, and a double + * quote can no longer close the attribute early and truncate the name. + * + * @static + * @param {string} text + * @returns {string} + */ + static getAriaLabelText(text) { + return Utils.escapeAttributeValue(Utils.getPlainText(text)); + } + /** * @static * @param {string} text @@ -452,6 +521,42 @@ class DomUtils { $ele.setAttribute(name, value); } + /** + * @param {HTMLElement} $ele + * @param {string} name + */ + static removeAttr($ele, name) { + if (!$ele) { + return; + } + $ele.removeAttribute(name); + } + + /** + * Set an aria-* attribute when the state applies, remove it otherwise. + * + * Preferred over writing `aria-x="false"` for states whose absence is meaningful + * (aria-required, aria-invalid): a literal "false" is valid but adds noise that some + * screen readers still verbalise. + * + * @param {HTMLElement | NodeListOf} $ele + * @param {string} name + * @param {boolean} isSet + * @param {string} [value='true'] + */ + static toggleAria($ele, name, isSet, value = 'true') { + if (!$ele) { + return; + } + DomUtils.getElements($ele).forEach($this => { + if (isSet) { + $this.setAttribute(`aria-${name}`, value); + } else { + $this.removeAttribute(`aria-${name}`); + } + }); + } + /** * @param {HTMLElement} $from * @param {HTMLElement} $to @@ -600,7 +705,21 @@ class DomUtils { // @ts-ignore Object.entries(data).forEach(([k, v]) => { if (v !== undefined) { - html += ` ${k}="${v}" `; + /** + * Quotes are escaped here, at the attribute boundary, because this is the only place + * that knows the value is about to be wrapped in double quotes. + * + * The caller that matters is getTooltipAttrText(), which passes option labels through + * to data-tooltip. It used to escape quotes itself but only when containsHTML(label) + * was true, so a payload with no tag in it - `x" data-pwned="1" z="` - went in raw and + * put a live attribute on the value-tag element. Escaping unconditionally here removes + * the condition, and the parser turns " back into a quote, so the attribute still + * reads back as the original string. + * + * String(), not Utils.getString(): the latter maps `false` to '', and some of these + * attributes carry real boolean values (data-tooltip-ellipsis-only, -allow-html). + */ + html += ` ${k}="${Utils.replaceDoubleQuotesWithHTML(String(v))}" `; } }); return html; @@ -672,7 +791,7 @@ const nativeProps = ['autofocus', 'class', 'disabled', 'id', 'multiple', 'name', // the class below has been evaluated (see the assignment at the bottom of this file). // eslint-disable-next-line prefer-const let attrPropsMapping; -const dataProps = ['additionalClasses', 'additionalDropboxClasses', 'additionalDropboxContainerClasses', 'additionalToggleButtonClasses', 'aliasKey', 'allOptionsSelectedText', 'allowNewOption', 'alwaysShowSelectedOptionsCount', 'alwaysShowSelectedOptionsLabel', 'ariaLabelledby', 'ariaLabelText', 'ariaLabelClearButtonText', 'ariaLabelTagClearButtonText', 'ariaLabelSearchClearButtonText', 'autoSelectFirstOption', 'clearButtonText', 'descriptionKey', 'disableAllOptionsSelectedText', 'disableOptionGroupCheckbox', 'disableSelectAll', 'disableValidation', 'dropboxWidth', 'dropboxWrapper', 'emptyValue', 'enableSecureText', 'focusSelectedOptionOnOpen', 'hasOptionDescription', 'hideClearButton', 'hideValueTooltipOnSelectAll', 'keepAlwaysOpen', 'labelKey', 'markSearchResults', 'maxValues', 'maxWidth', 'minValues', 'moreText', 'noOfDisplayValues', 'noOptionsText', 'noSearchResultsText', 'optionHeight', 'optionSelectedText', 'optionsCount', 'optionsSelectedText', 'popupDropboxBreakpoint', 'popupPosition', 'position', 'search', 'searchByStartsWith', 'searchDelay', 'searchFormLabel', 'searchGroup', 'searchNormalize', 'searchPlaceholderText', 'selectAllOnlyVisible', 'selectAllText', 'setValueAsArray', 'showDropboxAsPopup', 'showOptionsOnlyOnSearch', 'showSecureTextWarning', 'showSelectedOptionsFirst', 'showValueAsTags', 'silentInitialValueSet', 'textDirection', 'tooltipAlignment', 'tooltipFontSize', 'tooltipMaxWidth', 'updatePositionThrottle', 'useGroupValue', 'valueKey', 'zIndex']; +const dataProps = ['additionalClasses', 'additionalDropboxClasses', 'additionalDropboxContainerClasses', 'additionalToggleButtonClasses', 'aliasKey', 'allOptionsSelectedText', 'allowNewOption', 'alwaysShowSelectedOptionsCount', 'alwaysShowSelectedOptionsLabel', 'ariaLabelledby', 'ariaLabelText', 'ariaLabelClearButtonText', 'ariaLabelTagClearButtonText', 'ariaLabelSearchClearButtonText', 'autoSelectFirstOption', 'clearButtonText', 'descriptionKey', 'disableAllOptionsSelectedText', 'disableOptionGroupCheckbox', 'disableSelectAll', 'disableValidation', 'dropboxWidth', 'dropboxWrapper', 'emptyValue', 'enableSecureText', 'focusSelectedOptionOnOpen', 'hasOptionDescription', 'hideClearButton', 'hideValueTooltipOnSelectAll', 'keepAlwaysOpen', 'labelKey', 'markSearchResults', 'maxValues', 'maxWidth', 'minValues', 'loadingText', 'minValuesErrorText', 'moreText', 'noOfDisplayValues', 'noOptionsSelectedText', 'noOptionsText', 'noSearchResultsText', 'optionHeight', 'optionSelectedText', 'optionsCount', 'optionsSelectedText', 'popupDropboxBreakpoint', 'popupPosition', 'position', 'requiredErrorText', 'search', 'searchByStartsWith', 'searchDelay', 'searchFormLabel', 'searchGroup', 'searchNormalize', 'searchPlaceholderText', 'searchResultText', 'searchResultsText', 'selectAllOnlyVisible', 'selectAllText', 'selectedText', 'setValueAsArray', 'showDropboxAsPopup', 'showOptionsOnlyOnSearch', 'showSecureTextWarning', 'showSelectedOptionsFirst', 'showValueAsTags', 'silentInitialValueSet', 'textDirection', 'tooltipAlignment', 'tooltipFontSize', 'tooltipMaxWidth', 'updatePositionThrottle', 'useGroupValue', 'valueKey', 'zIndex']; /** Class representing VirtualSelect */ class VirtualSelect { @@ -708,9 +827,20 @@ class VirtualSelect { let toggleButtonClasses = 'vscomp-toggle-button'; const valueTooltip = this.showValueAsTags ? '' : this.getTooltipAttrText(this.placeholder, true, true); const clearButtonTooltip = this.getTooltipAttrText(this.clearButtonText); - const ariaLabelledbyText = this.ariaLabelledby ? `aria-labelledby="${this.ariaLabelledby}"` : ''; - const ariaLabelText = this.ariaLabelText ? `aria-label="${this.ariaLabelText}"` : ''; - const ariaLabelClearBtnTxt = this.ariaLabelClearButtonText ? `aria-label="${this.ariaLabelClearButtonText}"` : ''; + /** + * These props are developer-supplied but still reach an attribute directly, and none of them + * passes through secureText() - so enableSecureText never protected them. A double quote + * closed the attribute early: the payload after it was parsed as markup, and the accessible + * name kept only the prefix, which is a WCAG 4.1.2 defect as much as an injection. + * + * getAriaLabelText() for the accessible names, because it is what AI-14 already applies to + * option and group labels: strip markup, then escape quotes. Plain quote escaping for + * aria-labelledby, which is an IDREF list rather than prose - stripping tags there would hide + * a caller error instead of fixing it. + */ + const ariaLabelledbyText = this.ariaLabelledby ? `aria-labelledby="${Utils.replaceDoubleQuotesWithHTML(Utils.getString(this.ariaLabelledby))}"` : ''; + const ariaLabelText = this.ariaLabelText ? `aria-label="${Utils.getAriaLabelText(this.ariaLabelText)}"` : ''; + const ariaLabelClearBtnTxt = this.ariaLabelClearButtonText ? `aria-label="${Utils.getAriaLabelText(this.ariaLabelClearButtonText)}"` : ''; let isExpanded = false; if (this.additionalClasses) { wrapperClasses += ` ${Utils.sanitizeClassNames(this.additionalClasses)}`; @@ -751,7 +881,7 @@ class VirtualSelect { const html = `
- +
${this.placeholder} @@ -766,7 +896,12 @@ class VirtualSelect { ${this.renderDropbox({ wrapperClasses })} -
`; +
+ +
+ +
`; this.$ele.innerHTML = html; this.$body = document.querySelector('body'); this.$wrapper = this.$ele.querySelector('.vscomp-wrapper'); @@ -782,6 +917,33 @@ class VirtualSelect { this.$clearButton = this.$ele.querySelector('.vscomp-clear-button'); this.$valueText = this.$ele.querySelector('.vscomp-value'); this.$hiddenInput = this.$ele.querySelector('.vscomp-hidden-input'); + + /** + * The submitting field's name is set as a DOM property, not interpolated into the template. + * + * `name="${this.name}"` made the attribute an HTML sink: a double quote closed it early, so + * the remainder of the value was parsed as markup (real elements, an injection) while the + * field kept only the truncated prefix - or, when the payload also swallowed the following + * `class="vscomp-hidden-input"`, no field was found at all and the first setValue() threw + * inside the constructor. Either way the form silently stopped submitting the right name, + * and that included legitimate names such as `items["a"]`. + * + * A property assignment performs no HTML parsing, so there is nothing to break out of and + * nothing to escape - which is also why `name` no longer goes through secureText(): the + * escaping only ever protected this sink, and applying it here corrupted the submitted + * field name into `items["a"]`. + */ + this.$hiddenInput.name = this.name; + + /** + * Both live outside the wrapper, as siblings, because the wrapper is the combobox: for an + * instance mounted without ariaLabelText/ariaLabelledby the combobox takes its accessible + * name from its contents, and visually-hidden text still joins that computation - so a + * status update or validation message inside it would be read as part of the field's *name*. + * A sibling can be announced (live region) or associated (aria-describedby) without that. + */ + this.$liveRegion = this.$ele.querySelector('.vscomp-live-region'); + this.$errorMessage = this.$ele.querySelector('.vscomp-error-message'); this.$dropbox = this.$dropboxContainer.querySelector('.vscomp-dropbox'); this.$dropboxCloseButton = this.$dropboxContainer.querySelector('.vscomp-dropbox-close-button'); this.$dropboxContainerBottom = this.$dropboxContainer.querySelector('.vscomp-dropbox-container-bottom'); @@ -811,7 +973,9 @@ class VirtualSelect {
-
+
@@ -844,8 +1008,16 @@ class VirtualSelect { return html; } renderOptions() { - // Calculate ARIA metadata before rendering to ensure it's always up to date - this.calculateAriaMetadata(); + /** + * The ARIA scan walks every option, so running it per render made scrolling O(n) per + * event (~3.9 ms/call at 100k). aria-setsize/aria-posinset only change when the + * filtered set or its order changes, never when the virtualisation window moves, so + * recompute on a dirty flag instead. Everything that alters the set marks it dirty. + */ + if (this.ariaMetadataDirty) { + this.calculateAriaMetadata(); + this.ariaMetadataDirty = false; + } let html = ''; const visibleOptions = this.getVisibleOptions(); let checkboxHtml = ''; @@ -908,14 +1080,14 @@ class VirtualSelect { ariaDisabledText = 'aria-disabled="true"'; } if (d.isGroupTitle) { - groupName = d.label; + /** carried into every child's aria-label below, so strip markup once here */ + groupName = Utils.getAriaLabelText(d.label); optionClasses += ' group-title'; if (disableOptionGroupCheckbox) { leftSection = ''; } else if (this.multiple) { - const groupLabel = Utils.replaceDoubleQuotesWithHTML(Utils.getString(d.label)); - const selectAllText = Utils.replaceDoubleQuotesWithHTML(Utils.getString(this.selectAllText)); - ariaLabel = `aria-label="${groupLabel}, ${selectAllText}"`; + const selectAllText = Utils.getAriaLabelText(this.selectAllText); + ariaLabel = `aria-label="${groupName}, ${selectAllText}"`; } } if (isSelected) { @@ -932,13 +1104,13 @@ class VirtualSelect { * is on - an XSS bypass. secureText is a no-op when enableSecureText is disabled, * keeping the existing behaviour for consumers that intentionally pass raw text. */ - const groupNameText = this.secureText(Utils.getString(d.customData.group_name)); - const groupDescText = this.secureText(Utils.getString(d.customData.description)); + const groupNameText = Utils.getAriaLabelText(this.secureText(Utils.getString(d.customData.group_name))); + const groupDescText = Utils.getAriaLabelText(this.secureText(Utils.getString(d.customData.description))); groupName = d.customData.group_name !== undefined ? `${groupNameText}, ` : ''; const optionDesc = d.customData.description !== undefined ? ` ${groupDescText},` : ''; - ariaLabel = `aria-label="${groupName} ${d.label}, ${optionDesc}"`; + ariaLabel = `aria-label="${groupName} ${Utils.getAriaLabelText(d.label)}, ${optionDesc}"`; } else { - ariaLabel = `aria-label="${groupName}, ${d.label}"`; + ariaLabel = `aria-label="${groupName}, ${Utils.getAriaLabelText(d.label)}"`; } } if (hasLabelRenderer) { @@ -964,8 +1136,23 @@ class VirtualSelect { ariaAttrs += ` aria-posinset="${d.filteredIndex}"`; } } + + /** + * The option value is an untrusted string going straight into an attribute, so a double + * quote in it closed data-value early and everything after it was parsed as markup - a + * value of `x" data-pwned="1" z="` put a live data-pwned attribute on the option row, + * whether or not enableSecureText was on. + * + * `&` is escaped here as well as `"`, because the value is now stored verbatim (it reaches + * no innerHTML sink, so escaping it only made the option unaddressable - see secureText). + * Both together keep the attribute round-tripping: the parser turns `&` and `"` + * back into `&` and `"`, and setOptionAttr() rewrites data-value through the DOM API on + * every render anyway. + */ + const optionValueAttr = Utils.escapeAttributeValue(d.value); html += `
${leftSection} @@ -988,20 +1175,40 @@ class VirtualSelect { let checkboxHtml = ''; let searchInput = ''; if (this.multiple && !this.disableSelectAll) { - checkboxHtml = ` + /** + * role="checkbox" + aria-checked so the control is announced as a checkbox and its + * state changes are audible. Without them it exposed as a generic element and every + * select/deselect was silent to assistive technology (WCAG 4.1.2 / 1.3.1). + * aria-checked is kept in sync by toggleAllOptionsClass(). + */ + /** + * selectAllText has two sinks, and only the attribute one is escaped. + * + * The visible label below is rendered as HTML and that works today - `Pick all` + * produces a real - so escaping it would be a visible regression for anyone styling + * the Select All label. The accessible name, by contrast, was raw: a quote broke out of + * the attribute, and markup was announced as tag soup. getAriaLabelText() is the same + * treatment the group-header aria-label a few methods up already applies to this exact + * prop, which is why that sink was safe while this one was not. + */ + checkboxHtml = ` ${this.selectAllText} `; } if (this.hasSearch) { - const ariaLabelSearchClearBtnTxt = this.ariaLabelSearchClearButtonText ? `aria-label="${this.ariaLabelSearchClearButtonText}"` : ''; + const ariaLabelSearchClearBtnTxt = this.ariaLabelSearchClearButtonText ? `aria-label="${Utils.getAriaLabelText(this.ariaLabelSearchClearButtonText)}"` : ''; searchInput = ` - + ×`; } const html = `
@@ -1132,14 +1339,29 @@ class VirtualSelect { e.preventDefault(); this.focusFirstVisibleOption(); } - if (document.activeElement === this.$toggleAllButton && key === 13) { + + /** + * Space is the expected activation key for role="checkbox"; Enter is kept for + * backwards compatibility. preventDefault stops Space from scrolling the page + * (the previous behaviour, since the key was unhandled here). + */ + if (document.activeElement === this.$toggleAllButton && (key === 13 || key === 32)) { + e.preventDefault(); this.toggleAllOptions(); return; } - // Handle the Escape key when showing the dropdown as a popup, closing it + /** + * Escape must close the dropdown in every layout (WCAG 2.1.1 / 2.1.2). + * The element that contains the focused node differs by layout: with an external + * `dropboxWrapper` the dropbox is portalled out of $wrapper, so containment has to be + * tested against $dropboxWrapper. In every other case - including the default + * `dropboxWrapper: 'self'` on desktop - the dropbox lives inside $wrapper. Selecting + * $dropboxWrapper unconditionally for non-popup layouts left it `undefined` under the + * default config, so the branch never ran and Escape did nothing. + */ if (key === 27 || e.key === 'Escape') { - const wrapper = this.showAsPopup ? this.$wrapper : this.$dropboxWrapper; + const wrapper = this.hasDropboxWrapper && !this.showAsPopup ? this.$dropboxWrapper : this.$wrapper; if (wrapper && (document.activeElement === wrapper || wrapper.contains(document.activeElement)) && !this.keepAlwaysOpen) { this.closeDropbox(); return; @@ -1157,33 +1379,34 @@ class VirtualSelect { this.openDropbox(); } } - onDownArrowPress(e) { - // Allow default behavior (cursor movement) when search input is focused - if (document.activeElement === this.$searchInput) { - return; - } + + /** + * Move the highlight without moving DOM focus. + * + * Previously both arrow handlers bailed out whenever the search input had focus, to let + * the caret move. But opening the dropdown focuses the search input, so in the default + * flow the arrows did nothing at all and no option was ever highlighted (WCAG 2.1.1). + * The APG editable-combobox pattern is what applies here: Up/Down drive the list while + * focus stays in the field, and the active option is published as aria-activedescendant. + * + * @param {KeyboardEvent} e + * @param {'next' | 'previous'} direction + */ + navigateOptions(e, direction) { e.preventDefault(); if (this.isOpened()) { this.focusOption({ - direction: 'next' + direction }); } else { this.openDropbox(); } } + onDownArrowPress(e) { + this.navigateOptions(e, 'next'); + } onUpArrowPress(e) { - // Allow default behavior (cursor movement) when search input is focused - if (document.activeElement === this.$searchInput) { - return; - } - e.preventDefault(); - if (this.isOpened()) { - this.focusOption({ - direction: 'previous' - }); - } else { - this.openDropbox(); - } + this.navigateOptions(e, 'previous'); } onBackspaceOrDeletePress(e) { if (e.target === this.$wrapper) { @@ -1220,8 +1443,24 @@ class VirtualSelect { this.reset(); } } + + /** + * Scroll fires many times per drag and each event triggered a full re-render + * (~9.5 ms at 100k unthrottled, ~44 ms at 4x CPU), so the main thread stayed blocked for + * the whole gesture. Coalesce into at most one re-render per animation frame; the pending + * frame is cancelled in destroy() so it cannot run against a torn-down instance. + */ onOptionsScroll() { - this.setVisibleOptions(true); + if (this.scrollAnimationFrame) { + return; + } + this.scrollAnimationFrame = requestAnimationFrame(() => { + this.scrollAnimationFrame = null; + if (this.isDestroyed) { + return; + } + this.setVisibleOptions(true); + }); } onOptionsClick(e) { const $option = e.target.closest('.vscomp-option'); @@ -1453,6 +1692,12 @@ class VirtualSelect { if (this.autofocus) { this.focus(); } + + /** + * Marks the end of construction. Live-region announcements are suppressed until + * here so an initial value or the first render does not speak on page load. + */ + this.isInitialized = true; } catch (e) { this.destroy(); throw e; @@ -1502,6 +1747,15 @@ class VirtualSelect { afterSetSearchValue() { if (this.hasServerSearch) { clearTimeout(this.serverSearchTimeout); + + /** + * A search the user types is never silent, whatever state a previous close left behind. + * The other half of the lifecycle lives in closeDropbox()/openDropbox(): closing marks + * the instance silent *after* its own setSearchValue('') runs, so it does not matter + * what this assignment does during the close - but it must not matter, which is why + * this is unconditional rather than `= this.isClosing`. + */ + this.isSilentServerSearch = false; this.serverSearchTimeout = setTimeout(() => { this.serverSearch(); }, this.searchDelay); @@ -1511,9 +1765,16 @@ class VirtualSelect { if (this.selectAllOnlyVisible) { this.toggleAllOptionsClass(); } - this.focusOption({ - focusFirst: true - }); + + /** a closing dropbox must not take a highlight back - see closeDropbox() */ + if (!this.isClosing) { + this.focusOption({ + focusFirst: true + }); + } + if (!this.hasServerSearch) { + this.announceSearchResults(); + } } afterSetVisibleOptionsCount() { this.scrollToTop(); @@ -1536,7 +1797,19 @@ class VirtualSelect { this.setSearchValue('', false, true); } if (!keepValue) { - this.reset(); + /** + * reset() validates, and validation announces - so replacing the options used to speak a + * validation failure for an interaction the user never made. Scoped to this one call rather + * than the whole method, and released in a finally: a stuck flag would silently suppress + * every later error announcement, which is far harder to diagnose than an exception (the + * lesson from the isClosing guard in closeDropbox()). + */ + this.isRefreshingOptions = true; + try { + this.reset(); + } finally { + this.isRefreshingOptions = false; + } } } /** after event methods - end */ @@ -1599,6 +1872,14 @@ class VirtualSelect { this.optionsSelectedText = options.optionsSelectedText; this.optionSelectedText = options.optionSelectedText; this.allOptionsSelectedText = options.allOptionsSelectedText; + /** live-region announcement texts (see announce/getResultsCountMessage) */ + this.searchResultsText = options.searchResultsText; + this.searchResultText = options.searchResultText; + this.noOptionsSelectedText = options.noOptionsSelectedText; + this.selectedText = options.selectedText; + this.loadingText = options.loadingText; + this.requiredErrorText = options.requiredErrorText; + this.minValuesErrorText = options.minValuesErrorText; this.clearButtonText = options.clearButtonText; this.moreText = options.moreText; this.placeholder = options.placeholder; @@ -1613,7 +1894,8 @@ class VirtualSelect { this.zIndex = parseInt(options.zIndex, 10); this.maxValues = parseInt(options.maxValues, 10); this.minValues = parseInt(options.minValues, 10); - this.name = this.secureText(options.name); + /** not escaped: the only sink is the hidden input's `name` *property* (see renderWrapper) */ + this.name = options.name; this.additionalClasses = options.additionalClasses; this.additionalDropboxClasses = options.additionalDropboxClasses; this.additionalDropboxContainerClasses = options.additionalDropboxContainerClasses; @@ -1635,6 +1917,16 @@ class VirtualSelect { this.showDuration = parseInt(options.showDuration, 10); this.hideDuration = parseInt(options.hideDuration, 10); + /** + * The open/close animation is driven from JS as well as CSS, so the stylesheet's + * prefers-reduced-motion rule alone would still leave the popover animating for + * showDuration/hideDuration milliseconds. Honour the preference here too. + */ + if (Utils.prefersReducedMotion()) { + this.showDuration = 0; + this.hideDuration = 0; + } + /** @type {string[]} */ this.selectedValues = []; /** @type {virtualSelectOption[]} */ @@ -1663,13 +1955,27 @@ class VirtualSelect { this.optionsHeight = this.getOptionsHeight(); this.uniqueId = this.getUniqueId(); this.shouldFocusWrapperOnClose = true; // Initialize focus management property + this.isClosing = false; + /** true from closeDropbox() until the next openDropbox() - see closeDropbox() */ + this.isSilentServerSearch = false; this.ariaSetSize = 0; + this.ariaMetadataDirty = true; } /** * @param {virtualSelectOptions} options */ setDefaultProps(options) { + const globalDefaults = VirtualSelect.globalDefaults; + + /** + * Resolve a prop across the precedence chain for the few defaults that are derived + * from another prop, so a page-level default still drives them. + * @param {string} key + */ + const resolve = key => options[key] !== undefined ? options[key] : globalDefaults[key]; + const keepAlwaysOpen = resolve('keepAlwaysOpen'); + const hasOptionDescription = resolve('hasOptionDescription'); const defaultOptions = { dropboxWrapper: 'self', valueKey: 'value', @@ -1693,10 +1999,19 @@ class VirtualSelect { moreText: 'more...', optionsSelectedText: 'options selected', optionSelectedText: 'option selected', + /** live-region announcements (WCAG 4.1.3) - overridable for localisation */ + searchResultsText: 'results available', + searchResultText: 'result available', + noOptionsSelectedText: 'No options selected', + selectedText: 'selected', + loadingText: 'Loading results', + /** validation messages; {count} in minValuesErrorText is replaced with minValues */ + requiredErrorText: 'This field is required', + minValuesErrorText: 'Select at least {count} options', allOptionsSelectedText: 'All', placeholder: 'Select', position: 'bottom left', - zIndex: options.keepAlwaysOpen ? 1 : 2, + zIndex: keepAlwaysOpen ? 1 : 2, tooltipFontSize: '14px', tooltipAlignment: 'center', tooltipMaxWidth: '300px', @@ -1718,11 +2033,38 @@ class VirtualSelect { showDuration: 300, hideDuration: 200 }; - if (options.hasOptionDescription) { + if (hasOptionDescription) { defaultOptions.optionsCount = 4; defaultOptions.optionHeight = '50px'; } - return Object.assign(defaultOptions, options); + + /** + * Precedence: per-instance options > page-level globals > built-in defaults. + * Globals let a host turn a policy on once (notably enableSecureText) instead of + * repeating it at every call site, while an instance can still opt out explicitly. + */ + /** + * `undefined` means "not supplied", so those keys are dropped before merging. + * + * Object.assign copies own enumerable keys *including* ones whose value is undefined, so a prop + * forwarded from an unset variable - `enableSecureText: wrapper.sanitizeValues`, the shape a + * host wrapper naturally produces - overwrote the page-level global instead of falling back to + * it. A host could call setGlobalDefaults({ enableSecureText: true }) and still get escaping + * off at every such call site, with nothing to show it had been overridden. + * + * This also makes the merge agree with the resolve() helper above, which already treats + * undefined as absent; the two disagreed inside the same method. + */ + const supplied = source => { + const result = {}; + Object.keys(source || {}).forEach(key => { + if (source[key] !== undefined) { + result[key] = source[key]; + } + }); + return result; + }; + return Object.assign(defaultOptions, supplied(globalDefaults), supplied(options)); } setPropsFromElementAttr(options) { const $ele = options.ele; @@ -1746,6 +2088,8 @@ class VirtualSelect { $ele.name = this.name; $ele.disabled = false; $ele.required = this.required; + /** expose the constraint itself, not just the failure (WCAG 3.3.1) */ + DomUtils.toggleAria(this.$allWrappers, 'required', this.required); $ele.autofocus = this.autofocus; $ele.multiple = this.multiple; $ele.form = $ele.closest('form'); @@ -1774,8 +2118,23 @@ class VirtualSelect { } } setValueMethod(newValue, silentChange) { - const valuesMapping = {}; - const valuesOrder = {}; + /** + * Option values are untrusted strings used as keys, so every value-keyed lookup in this + * file is built with Object.create(null) rather than `{}`. + * + * This is not about prototype pollution - `mapping['__proto__'] = true` on a plain object + * calls the inherited setter, which ignores a non-object value, so nothing is written and + * Object.prototype stays intact. The damage is to reads: `mapping['__proto__']` returns + * the inherited Object.prototype, which is truthy but never `=== true`, and these lookups + * all compare against `true`. An option whose value is `__proto__` was therefore + * selectable by click (that path reads data-value, not a mapping) but invisible to + * setValue / setDisabledOptions / setEnabledOptions, so a selection the app could read + * back could not be restored - and under allowNewOption it was mistaken for an unknown + * value and duplicated. A null prototype has no inherited members, so an arbitrary string + * key behaves like any other. + */ + const valuesMapping = Object.create(null); + const valuesOrder = Object.create(null); let validValues = []; const isMultiSelect = this.multiple; // Normalize input value first @@ -1838,7 +2197,7 @@ class VirtualSelect { setGroupOptionsValue(preparedValues) { const selectedValues = []; const selectedGroups = {}; - const valuesMapping = {}; + const valuesMapping = Object.create(null); preparedValues.forEach(d => { valuesMapping[d] = true; }); @@ -1899,7 +2258,7 @@ class VirtualSelect { } } else { disabledOptionsArr = disabledOptions.map(d => d.toString()); - const disabledOptionsMapping = {}; + const disabledOptionsMapping = Object.create(null); disabledOptionsArr.forEach(d => { disabledOptionsMapping[d] = true; }); @@ -1933,7 +2292,7 @@ class VirtualSelect { return d; }); } else { - const enabledOptionsMapping = {}; + const enabledOptionsMapping = Object.create(null); enabledOptions.forEach(d => { enabledOptionsMapping[d] = true; }); @@ -1968,7 +2327,7 @@ class VirtualSelect { const getAlias = this.getAlias.bind(this); let index = 0; let hasOptionGroup = false; - const disabledOptionsMapping = {}; + const disabledOptionsMapping = Object.create(null); let hasEmptyValueOption = false; this.disabledOptions.forEach(d => { disabledOptionsMapping[d] = true; @@ -1981,8 +2340,25 @@ class VirtualSelect { [labelKey]: d }; } - const value = secureText(getString(d[valueKey])); - const label = secureText(getString(d[labelKey])); + + /** + * `value` is stored verbatim; only `label` and `description` are escaped. + * + * Escaping is for HTML sinks, and the value has none: it goes into the `data-value` + * attribute (escaped there, at the boundary) and is otherwise only compared or used as a + * map key. Escaping it stored an identity the caller could not name - `a&b` became + * `a&b`, so setValue(['a&b']) matched nothing and a value read back could not be set + * again. + * + * The normalised search keys derive from the *raw* text for the same reason: they are + * matched against what the user types into the search box, which is never HTML-escaped. + * Deriving them from the escaped text meant no query could match text containing `&`, + * `<` or `>`. + */ + const rawValue = getString(d[valueKey]); + const rawLabel = getString(d[labelKey]); + const value = rawValue; + const label = secureText(rawLabel); const childOptions = d.options; const isGroupTitle = !!childOptions; const option = { @@ -1990,7 +2366,7 @@ class VirtualSelect { value, valueNormalized: value.toLowerCase(), label, - labelNormalized: this.searchNormalize && label.trim() !== '' ? Utils.normalizeString(label).toLowerCase() : label.toLowerCase(), + labelNormalized: this.searchNormalize && rawLabel.trim() !== '' ? Utils.normalizeString(rawLabel).toLowerCase() : rawLabel.toLowerCase(), alias: getAlias(d[aliasKey]), isVisible: convertToBoolean(d.isVisible, true), isNew: d.isNew || false, @@ -2008,9 +2384,10 @@ class VirtualSelect { option.groupIndex = d.groupIndex; } if (hasOptionDescription) { - const description = secureText(getString(d[descriptionKey])); - option.description = description; - option.descriptionNormalized = this.searchNormalize && description.trim() !== '' ? Utils.normalizeString(description).toLowerCase() : description.toLowerCase(); + const rawDescription = getString(d[descriptionKey]); + option.description = secureText(rawDescription); + /** normalised from the raw text, so a query containing `&` can match - see above */ + option.descriptionNormalized = this.searchNormalize && rawDescription.trim() !== '' ? Utils.normalizeString(rawDescription).toLowerCase() : rawDescription.toLowerCase(); } if (d.customData) { option.customData = d.customData; @@ -2056,7 +2433,7 @@ class VirtualSelect { /** merging already selected options details with new options */ if (selectedOptions.length) { - const newOptionsValueMapping = {}; + const newOptionsValueMapping = Object.create(null); optionsUpdated = true; newOptions.forEach(d => { newOptionsValueMapping[d.value] = true; @@ -2090,11 +2467,32 @@ class VirtualSelect { } this.setVisibleOptionsCount(); DomUtils.removeClass(this.$allWrappers, 'server-searching'); + + /** + * Replace the "loading" message with the outcome of the fetch - for an open dropdown. + * + * isOpened() alone is not enough: the `closed` class arrives with the hide transition, + * so a response landing just after Escape still saw an "open" dropdown. The silent flag + * (see closeDropbox) covers that window and the whole closed period; opening lifts it. + * + * The count always describes the list as rendered *now*, not the fetch that triggered it. + * setServerOptions() carries no request identity, so responses cannot be matched to + * searches - when a stale response overwrites the list of an open dropdown, what is + * announced is exactly what the user sees, and the newer response re-announces when it + * lands. The local path announces the currently visible matches on the same principle + * (announceSearchResults additionally requires focus in the search input, which a + * response arriving whenever the host answers cannot demand). + */ + if (this.isInitialized && !this.isSilentServerSearch && this.isOpened()) { + this.announce(this.getResultsCountMessage()); + } } setSelectedOptions() { this.selectedOptions = this.options.filter(d => d.isSelected); } setSortedOptions() { + /** order drives aria-posinset */ + this.ariaMetadataDirty = true; let sortedOptions = [...this.options]; if (this.showSelectedOptionsFirst && this.selectedValues.length) { if (this.hasOptionGroup) { @@ -2178,8 +2576,26 @@ class VirtualSelect { DomUtils.toggleClass(this.$allWrappers, 'max-value-selected', this.isMaxValuesSelected); DomUtils.setAttr(this.$clearButton, 'tabindex', hasValue ? '0' : '-1'); DomUtils.setAria(this.$clearButton, 'hidden', hasValue === false); + let isValid = true; if (!disableValidation) { - this.validate(); + isValid = this.validate(); + } + + /** + * Selection changes are otherwise conveyed only by the (visual) value text. + * Guarded on isInitialized so a value supplied at construction time is not + * announced before the user has interacted with anything. + * + * Skipped when validation just failed. validate() announces its message through the same + * polite region, and a polite region is read from its *final* content - so announcing the + * selection summary here overwrote the validation message in the same tick and the user + * never heard it. That silenced every interactive path (the clear button, deselecting below + * minValues) while still setting aria-invalid and showing the message on screen, which is + * the 3.3.1 failure this region exists to fix. The error is the more urgent of the two, and + * it already implies the selection state. + */ + if (this.isInitialized && isValid) { + this.announce(this.getSelectionMessage()); } if (!disableEvent) { DomUtils.dispatchEvent(this.$ele, 'change', true); @@ -2224,17 +2640,37 @@ class VirtualSelect { valueText.push(label); selectedValuesCount += 1; if (showValueAsTags) { - // Will cause text overflow in runtime and if so,the tooltip information is prepared - const valueTooltipForTags = Utils.willTextOverflow($valueText.parentElement, label) ? this.getTooltipAttrText(label, false, true) : ''; + /** + * The tooltip is attached to the tag's *content* span, with ellipsisOnly, so the + * tooltip plugin runs `scrollWidth > offsetWidth` on the real box at hover time. + * + * This used to be decided here, before the tag existed, by measuring the label + * off-screen against `.vscomp-toggle-button` - an element ~73px wider than the space + * the tag text actually gets, at that element's 14px rather than the tag's 12px. Both + * errors are gone by construction once the rendered box is the measurement (#487). + * + * The content span rather than `.vscomp-value-tag`: the tag is `inline-flex` and its + * content span carries `width: calc(100% - 24px)`, so the span clips while the tag + * never reports an overflow of its own - measured, a clipped tag reads + * scrollWidth 260 / offsetWidth 262. + * + * Deferring to hover also means no layout work at render, and a correct answer after + * a resize or when the control is first rendered inside a hidden container - none of + * which a render-time measurement can give. It matches how the non-tag value text has + * always worked (see getToggleButtonHtml). + */ + const valueTagTooltip = this.getTooltipAttrText(label, true, true); - // replace is nedded to remove html tags from aria-label (ex: when there is an icon in the label) + /** markup in the label would otherwise land in the accessible name; a double + * quote in it would break out of the attribute entirely */ let ariaLabelClearBtnTxt = ''; if (this.ariaLabelTagClearButtonText) { - const stripHtmlLabel = label.replace(/<[^>]+>/ig, '').trim(); - ariaLabelClearBtnTxt = `aria-label="${stripHtmlLabel}, ${this.ariaLabelTagClearButtonText}"`; + const stripHtmlLabel = Utils.getAriaLabelText(label); + const clearButtonText = Utils.getAriaLabelText(this.ariaLabelTagClearButtonText); + ariaLabelClearBtnTxt = `aria-label="${stripHtmlLabel}, ${clearButtonText}"`; } - const valueTagHtml = ` - ${label} + const valueTagHtml = ` + ${label} { valuesMapping[d] = true; }); @@ -2501,7 +2950,7 @@ class VirtualSelect { return; } const setNewOption = this.setNewOption.bind(this); - const availableValuesMapping = {}; + const availableValuesMapping = Object.create(null); this.options.forEach(d => { availableValuesMapping[d.value] = true; }); @@ -2596,7 +3045,7 @@ class VirtualSelect { if (this.showSelectedOptionsFirst || !this.focusSelectedOptionOnOpen || selectedValues.length === 0) { return; } - const valuesMapping = {}; + const valuesMapping = Object.create(null); let selectedOptionIndex; selectedValues.forEach(d => { valuesMapping[d] = true; @@ -2671,9 +3120,11 @@ class VirtualSelect { return startIndex; } getTooltipAttrText(text, ellipsisOnly = false, allowHtml = false) { - const tootltipText = Utils.containsHTML(text) ? Utils.replaceDoubleQuotesWithHTML(text) : text; + /** quotes are escaped unconditionally by getAttributesText(); escaping again here would + * leave a literal " in the tooltip, and the old containsHTML() condition is what + * let a tag-free payload through in the first place */ const data = { - 'data-tooltip': tootltipText || '', + 'data-tooltip': text || '', 'data-tooltip-enter-delay': this.tooltipEnterDelay, 'data-tooltip-z-index': this.zIndex, 'data-tooltip-font-size': this.tooltipFontSize, @@ -2697,17 +3148,18 @@ class VirtualSelect { getString } = Utils; const secureText = this.secureText.bind(this); - const value = secureText(getString(data.value)); - const label = secureText(getString(data.label)); - const description = secureText(getString(data.description)); + /** value stored verbatim, search keys derived from the raw text - see setOptions() */ + const rawValue = getString(data.value); + const rawLabel = getString(data.label); + const rawDescription = getString(data.description); return { index: data.index, - value, - valueNormalized: value.toLowerCase(), - label, - labelNormalized: this.searchNormalize && label.trim() !== '' ? Utils.normalizeString(label).toLowerCase() : label.toLowerCase(), - description, - descriptionNormalized: this.searchNormalize && description.trim() !== '' ? Utils.normalizeString(description).toLowerCase() : description.toLowerCase(), + value: rawValue, + valueNormalized: rawValue.toLowerCase(), + label: secureText(rawLabel), + labelNormalized: this.searchNormalize && rawLabel.trim() !== '' ? Utils.normalizeString(rawLabel).toLowerCase() : rawLabel.toLowerCase(), + description: secureText(rawDescription), + descriptionNormalized: this.searchNormalize && rawDescription.trim() !== '' ? Utils.normalizeString(rawDescription).toLowerCase() : rawDescription.toLowerCase(), alias: this.getAlias(data.alias), isCurrentNew: data.isCurrentNew || false, isNew: data.isNew || false, @@ -2733,7 +3185,7 @@ class VirtualSelect { return index; } getNewValue() { - const valuesMapping = {}; + const valuesMapping = Object.create(null); this.newValues.forEach(d => { valuesMapping[d] = true; }); @@ -2791,7 +3243,7 @@ class VirtualSelect { } }); if (keepSelectionOrder) { - const valuesOrder = {}; + const valuesOrder = Object.create(null); selectedValues.forEach((d, i) => { valuesOrder[d] = i; }); @@ -2805,7 +3257,7 @@ class VirtualSelect { labelKey, disabledOptions } = this; - const disabledOptionsValueMapping = {}; + const disabledOptionsValueMapping = Object.create(null); const result = []; disabledOptions.forEach(value => { disabledOptionsValueMapping[value] = true; @@ -2932,6 +3384,15 @@ class VirtualSelect { // Add to open instances VirtualSelect.openInstances.add(this); + + /** + * The silence a close imposed (see closeDropbox) must not outlive the closed state: + * from now on the list is visible, so a fetch that fires or resolves against this open + * dropdown describes what the user is looking at and has to be announced - including a + * host push refreshing the options, and the close-time reset when it lands only after + * the user has already reopened. + */ + this.isSilentServerSearch = false; DomUtils.setAttr(this.$dropboxWrapper, 'tabindex', '0'); DomUtils.setAria(this.$dropboxWrapper, 'hidden', false); DomUtils.setAttr(this.$dropboxContainerTop, 'tabindex', '0'); @@ -2942,6 +3403,13 @@ class VirtualSelect { DomUtils.setStyle(this.$dropboxContainer, 'display', 'inline-flex'); } else { DomUtils.dispatchEvent(this.$ele, 'beforeOpen'); + /** + * The wrapper is the one combobox and the one carrier of aria-expanded. The search + * input deliberately is not a second combobox: nesting one combobox inside another is + * a structure screen readers disagree on, and aria-expanded is not a supported state + * of the input's implicit textbox role - which does support the wiring the input + * needs (aria-autocomplete, aria-controls, aria-activedescendant). + */ DomUtils.setAria(this.$wrapper, 'expanded', true); } this.setDropboxWrapperWidth(); @@ -3002,9 +3470,21 @@ class VirtualSelect { } else { DomUtils.dispatchEvent(this.$ele, 'beforeClose'); DomUtils.setAria(this.$wrapper, 'expanded', false); - DomUtils.setAria(this.$wrapper, 'activedescendant', ''); - // Also clear aria-activedescendant on the listbox container - DomUtils.setAria(this.$dropboxContainer, 'activedescendant', ''); + /** + * No option is active once the list is gone - and the highlight has to go with it, + * here, synchronously. + * + * afterHidePopper() already calls removeOptionFocus(), but for popover-backed + * instances it only runs when the hide transition ends (~200ms later). Until then the + * previous highlight and `focusedOptionIndex` survived the close, so reopening within + * that window resumed navigation from the old position instead of the first option: + * the next Up/Down moved one step past where the user expected, which on a grouped + * multi-select meant Enter landed on the first child option instead of toggling the + * group title. removeOptionFocus() is a no-op when nothing is highlighted, so leaving + * the afterHidePopper() call in place costs nothing and still covers the silent path. + */ + this.removeOptionFocus(); + this.setActiveDescendant(''); } if (this.dropboxPopover && !isSilent) { this.dropboxPopover.hide(); @@ -3017,7 +3497,48 @@ class VirtualSelect { } else { this.afterHidePopper(); } - this.setSearchValue(''); + + /** + * Clearing the filter runs afterSetSearchValue(), which highlights the first visible + * option again. That undid the removeOptionFocus() above whenever the user had typed + * something: the highlight and aria-activedescendant came straight back on a combobox + * already marked aria-expanded="false", and focusOption() pulled DOM focus onto an option + * that is about to be display:none - so the keyboard position ended up on . + * + * isClosing is scoped to this one call rather than the whole method because everything + * above it (the wrapper refocus in particular) still needs the real state. The reset runs + * in a finally: if setSearchValue() ever threw, a stuck flag would silently stop the + * highlight coming back after *every* later filter clear, which is far harder to diagnose + * than the exception itself. + */ + this.isClosing = true; + try { + this.setSearchValue(''); + } finally { + this.isClosing = false; + } + + /** + * From here until the next open, no server-search announcement may reach the live region: + * the dropdown the messages would describe is gone. Closing spoke twice for an interaction + * the user never made - the reset above schedules a fetch of its own, which said + * loadingText one searchDelay after the dropbox had closed and then the result count when + * the host responded. The local path already refuses to announce a reset it performed + * itself (announceSearchResults); this flag is the same rule for the server path. + * + * A flag set for the whole closed period, rather than one latched onto the scheduled + * fetch, because the close cannot see everything that is still going to speak: + * setSearchValue('') early-returns when the user already emptied the box (leaving *their* + * pending fetch to fire after the close), and a response to an earlier search can land + * mid hide-transition, while isOpened() is still true. openDropbox() lifts the silence, + * so it cannot leak into the next open either. + * + * The reset fetch itself is deliberately left running - it is what restores the + * unfiltered list for the next open, since opening does not search. + */ + if (this.hasServerSearch) { + this.isSilentServerSearch = true; + } } afterHidePopper() { const isSilent = this.isSilentClose; @@ -3372,7 +3893,14 @@ class VirtualSelect { if (!isAllSelected && this.selectAllOnlyVisible && this.searchValue !== '' && (this.visibleOptionsCount > 0 || this.searchValue === '')) { isAllVisibleSelected = this.isAllOptionsSelected(true); } - DomUtils.toggleClass(this.$toggleAllCheckbox, 'checked', isAllSelected || isAllVisibleSelected); + const isChecked = isAllSelected || isAllVisibleSelected; + DomUtils.toggleClass(this.$toggleAllCheckbox, 'checked', isChecked); + /** + * Mirror the visual checked state onto the role="checkbox" host. This is the single + * point every selection path funnels through (select all, deselect all, per-option + * clicks, group toggles, setValue, reset), so the exposed state cannot drift. + */ + DomUtils.setAria(this.$toggleAllButton, 'checked', isChecked); this.isAllSelected = isAllSelected; } isAllOptionsSelected(visibleOnly) { @@ -3420,7 +3948,7 @@ class VirtualSelect { selectedValues, selectAllOnlyVisible } = this; - const valuesMapping = {}; + const valuesMapping = Object.create(null); const { removeItemFromArray } = Utils; @@ -3465,7 +3993,15 @@ class VirtualSelect { this.toggleOptionSelectedState($ele, isSelected); } toggleFocusedProp(index, isFocused = false) { - if (this.focusedOptionIndex) { + /** + * Explicitly against null, not truthiness. focusedOptionIndex comes from + * DomUtils.getData($ele, 'index') with no type, so today it is the *string* "0" and a + * truthiness test happens to pass for the first option. Normalise it to a number anywhere + * and index 0 would stop being cleared, so its `isFocused` prop would survive - and + * renderOptions() re-applies `.focused` and tabindex="0" from that prop, bringing the + * stale highlight back through the data path on the next render. + */ + if (this.focusedOptionIndex !== null && this.focusedOptionIndex !== undefined) { this.setOptionProp(this.focusedOptionIndex, 'isFocused', false); } this.setOptionProp(index, 'isFocused', isFocused); @@ -3494,7 +4030,18 @@ class VirtualSelect { }); this.afterValueSet(); if (formReset) { + /** + * A native form reset clears the error state, not just the colour that showed it. + * + * Removing `has-error` alone left aria-invalid="true" on the combobox and + * aria-describedby pointing at an error element that still held its text - so the control + * stayed announced as invalid, describing a message the user could no longer see, with no + * interaction able to clear it. setErrorMessage('') empties the text and drops + * aria-describedby, and does not announce (it only announces a non-empty message). + */ DomUtils.removeClass(this.$allWrappers, 'has-error'); + DomUtils.toggleAria(this.$allWrappers, 'invalid', false); + this.setErrorMessage(''); } DomUtils.dispatchEvent(this.$ele, 'reset'); } @@ -3524,6 +4071,8 @@ class VirtualSelect { removeNewOption() { const newOption = this.getNewOption(); if (newOption) { + /** removes a row from the filtered set */ + this.ariaMetadataDirty = true; this.removeOption(newOption.index); } } @@ -3643,6 +4192,17 @@ class VirtualSelect { serverSearch() { DomUtils.removeClass(this.$allWrappers, 'has-no-search-results'); DomUtils.addClass(this.$allWrappers, 'server-searching'); + + /** + * The spinner is a visual-only cue; announce that a fetch is in flight - but only for a + * dropdown the user can see. The silent flag covers the closed period (see closeDropbox); + * isOpened() covers fetches the component issued on its own while closed, such as the + * search reset showOptionsOnlyOnSearch forces during construction, which otherwise spoke + * loadingText on a page the user had not touched yet. + */ + if (this.isInitialized && !this.isSilentServerSearch && this.isOpened()) { + this.announce(this.loadingText); + } this.setSelectedOptions(); this.onServerSearch(this.searchValue, this); } @@ -3677,18 +4237,67 @@ class VirtualSelect { return true; } let hasError = false; + let errorText = ''; const { selectedValues, minValues } = this; - if (this.required && (Utils.isEmpty(selectedValues) || (/** required minium options not selected */ - this.multiple && minValues && selectedValues.length < minValues))) { - hasError = true; + if (this.required) { + if (Utils.isEmpty(selectedValues)) { + hasError = true; + errorText = this.requiredErrorText; + } else if (this.multiple && minValues && selectedValues.length < minValues) { + /** required minium options not selected */ + hasError = true; + errorText = Utils.getString(this.minValuesErrorText).replace('{count}', minValues); + } } DomUtils.toggleClass(this.$allWrappers, 'has-error', hasError); + + /** + * Previously the only signal was the `has-error` class recolouring the toggle button + * border: invisible to assistive technology and, being colour alone, a 1.4.1 failure. + * Expose the state (aria-invalid), give it a text message, point the combobox at that + * message (aria-describedby) and announce it. + */ + DomUtils.toggleAria(this.$allWrappers, 'invalid', hasError); + this.setErrorMessage(hasError ? errorText : ''); return !hasError; } + /** + * Show or clear the validation message and its association with the combobox. + * An empty message removes aria-describedby rather than pointing at empty text. + * + * @param {string} message + */ + setErrorMessage(message) { + if (!this.$errorMessage) { + return; + } + const text = message || ''; + this.$errorMessage.textContent = text; + DomUtils.toggleAria(this.$allWrappers, 'describedby', !!text, this.$errorMessage.id); + + /** + * The message is shown and exposed unconditionally, but only *announced* for something the + * user did. A live region is for status changes they caused. + * + * isInitialized keeps construction quiet: the initial setValueMethod() runs before that flag + * is set, so a page supplied with an invalid initial value used to load already speaking + * "Select at least 2 options". isRefreshingOptions keeps a programmatic data swap quiet: + * afterSetOptions() calls reset(), which validates, so replacing the options announced a + * failure for a field the user had never touched. + * + * Both are deliberately narrow. The interactive paths - the clear button, deselecting below + * minValues, and an explicit validate() from the application - must still announce, which is + * the whole point of routing validation through this region. + */ + if (text && this.isInitialized && !this.isRefreshingOptions) { + this.announce(text); + } + } + /** * setTimeout wrapper whose pending timers are tracked so they can be cleared on destroy(). * Prevents callbacks from running against a destroyed instance (stale DOM access / retention). @@ -3739,6 +4348,12 @@ class VirtualSelect { // Clear any other pending timeouts so their callbacks don't run on a destroyed instance this.clearManagedTimeouts(); + // Drop any queued scroll re-render so it cannot touch detached DOM + if (this.scrollAnimationFrame) { + cancelAnimationFrame(this.scrollAnimationFrame); + this.scrollAnimationFrame = null; + } + /** Remove all event listeners to prevent memory leaks and ensure proper cleanup */ this.removeEvents(); if (this.hasDropboxWrapper) { @@ -3767,8 +4382,20 @@ class VirtualSelect { if (!text || !this.enableSecureText) { return text; } - /** escape potentially harmful JavaScript so, label and value fields cannot trigger XSS */ - this.$secureText.nodeValue = Utils.replaceDoubleQuotesWithHTML(text); + + /** + * escape potentially harmful markup so label/value/description cannot trigger XSS. + * + * Quotes are deliberately *not* rewritten here. They were, and the text node's innerHTML + * then escaped the `&` that introduced - so `The "City" of Light` used to be stored as + * `The &quot;City&quot; of Light`, shown to the user as `The "City" of + * Light`, and made unsearchable, because labelNormalized derives from the stored text. + * Quotes only need escaping inside an attribute, and that now happens at each attribute + * boundary instead (data-value in renderOptions, DomUtils.getAttributesText) - which also + * covers the sinks this pre-escaping never reached, such as an attribute written while + * enableSecureText is off. + */ + this.$secureText.nodeValue = text; return this.$secureDiv.innerHTML; } @@ -3789,9 +4416,87 @@ class VirtualSelect { // eslint-disable-next-line no-console console.warn('[virtual-select] Option text (label, value, description) and any `customData` used in ' + 'markup are rendered as HTML and are NOT escaped because `enableSecureText` is disabled ' + '(the default, kept off for performance on large datasets). If any option text can come ' + 'from untrusted input, set `enableSecureText: true` to prevent XSS. ' + 'Docs: https://sa-si-dev.github.io/virtual-select/#/properties'); } + + /** + * Write a message into the instance's polite live region (WCAG 4.1.3 Status Messages). + * + * Identical consecutive messages are intentionally left alone: re-writing the same text + * produces no DOM mutation, so assistive technology does not repeat "No results found" + * on every further keystroke that still matches nothing. + * + * @param {string} message + */ + announce(message) { + if (!this.$liveRegion) { + return; + } + + /** + * Reduced to plain text because the region is written with textContent, so whatever is put + * there is read out literally. A single select announces the chosen label, and a label can + * carry both escaping and markup: with enableSecureText on the region said + * "Tom & Jerry selected", and decoding alone would only have turned that into + * " France selected". Neither is speech. Messages the component composes + * itself contain no markup, so this is a no-op for them. + */ + const text = Utils.getPlainText(message || ''); + if (this.$liveRegion.textContent !== text) { + this.$liveRegion.textContent = text; + } + } + + /** + * Message describing how many options the current filter matched. + * @returns {string} + */ + getResultsCountMessage() { + const count = this.filteredOptionsCount || 0; + if (count === 0) { + return this.noSearchResultsText; + } + return `${count} ${count === 1 ? this.searchResultText : this.searchResultsText}`; + } + + /** + * Message describing the current selection. + * @returns {string} + */ + getSelectionMessage() { + const count = this.selectedValues.length; + if (count === 0) { + return this.noOptionsSelectedText; + } + if (this.multiple) { + return `${count} ${count === 1 ? this.optionSelectedText : this.optionsSelectedText}`; + } + + /** option flags are updated before setValue(), so the label is already current */ + const label = this.getDisplayValue() || this.selectedValues[0]; + return `${label} ${this.selectedText}`; + } + + /** + * Announce the match count, but only while the user is actually searching. + * setSearchValue('') also runs on close and after a value is set; announcing there + * would read a stale count into the user's ear for an interaction they did not make. + */ + announceSearchResults() { + if (!this.isInitialized || !this.isOpened() || document.activeElement !== this.$searchInput) { + return; + } + this.announce(this.getResultsCountMessage()); + } toggleRequired(isRequired) { this.required = Utils.convertToBoolean(isRequired); this.$ele.required = this.required; + DomUtils.toggleAria(this.$allWrappers, 'required', this.required); + + /** dropping the requirement also drops any error it produced */ + if (!this.required) { + DomUtils.toggleClass(this.$allWrappers, 'has-error', false); + DomUtils.toggleAria(this.$allWrappers, 'invalid', false); + this.setErrorMessage(''); + } } toggleOptionSelectedState($ele, value) { let isSelected = value; @@ -3807,17 +4512,99 @@ class VirtualSelect { } DomUtils.toggleClass($ele, 'focused', isFocused); DomUtils.setAttr($ele, 'tabindex', isFocused ? '0' : '-1'); - if (document.activeElement !== this.$searchInput) { + + /** + * Only *taking* the highlight moves DOM focus. Clearing it used to focus the element it + * had just un-highlighted, which is either pointless (focusOption immediately focuses the + * new option anyway) or actively wrong: on close it pulled focus into a dropbox that is + * about to be hidden, fighting the wrapper refocus in closeDropbox(). + */ + if (isFocused && document.activeElement !== this.$searchInput) { $ele.focus(); } - if (isFocused) { - DomUtils.setAria(this.$wrapper, 'activedescendant', $ele.id); - // Also set aria-activedescendant on the listbox container for better screen reader support - DomUtils.setAria(this.$dropboxContainer, 'activedescendant', $ele.id); - } + + /** + * Publish the highlight on the elements that can carry it: the wrapper (the combobox) + * and the search input (a textbox, which also supports aria-activedescendant). It used + * to also go on $dropboxContainer, a plain div with no role, where aria-activedescendant + * is meaningless - and never on the search input, which is the element that actually + * holds focus while navigating. + */ + this.setActiveDescendant(isFocused ? $ele.id : ''); + } + + /** + * Point the combobox wrapper and the search input at the active option, or clear the + * reference. + * @param {string} optionId + */ + setActiveDescendant(optionId) { + DomUtils.toggleAria(this.$wrapper, 'activedescendant', !!optionId, optionId); + DomUtils.toggleAria(this.$searchInput, 'activedescendant', !!optionId, optionId); } /** static methods - start */ + + /** + * Set page-level default props applied to every instance created afterwards. + * + * The motivating case is security: option text is interpolated into innerHTML and is only + * escaped when `enableSecureText` is on, which it is not by default (escaping costs per + * option, and large trusted lists should not pay for it). A host that does render + * untrusted option text can turn escaping on once here rather than at every call site: + * + * VirtualSelect.setGlobalDefaults({ enableSecureText: true }); + * + * These are defaults, not overrides: an instance passing the prop explicitly still wins, + * so a host forwarding `enableSecureText` on every init must stop doing so (or forward + * `true`) for this to take effect. Calls merge, so features can be configured separately. + * Only instances created after the call are affected. + * + * @param {Partial} props + */ + static setGlobalDefaults(props) { + /** + * A non-object is ignored, not treated as "clear": a host forwarding an accidentally + * unset config variable would otherwise silently turn a page-wide security policy off. + * Clearing is an explicit act - resetGlobalDefaults(). A key can still be cleared + * individually by passing it with the value `undefined`, which setDefaultProps() + * treats as "not supplied". + */ + if (!props || typeof props !== 'object') { + return; + } + + /** `ele` and `options` are per-instance by nature and would alias state across instances */ + const safeProps = { + ...props + }; + delete safeProps.ele; + delete safeProps.options; + VirtualSelect.globalDefaults = { + ...VirtualSelect.globalDefaults, + ...safeProps + }; + } + + /** + * Drop every page-level default, restoring the built-in ones for instances created + * afterwards. The explicit counterpart to setGlobalDefaults(), which only ever merges. + */ + static resetGlobalDefaults() { + VirtualSelect.globalDefaults = {}; + } + + /** + * Currently active page-level defaults. + * A copy, so callers cannot mutate the live object. + * + * @returns {Partial} + */ + static getGlobalDefaults() { + return { + ...VirtualSelect.globalDefaults + }; + } static init(options) { let $eleArray = options.ele; if (!$eleArray) { @@ -4048,6 +4835,9 @@ VirtualSelect.lastInteractedInstance = null; // Ensures the "enableSecureText disabled" warning is logged at most once per page VirtualSelect.secureTextWarningShown = false; +// Page-level default props, applied under per-instance options (see setGlobalDefaults) +VirtualSelect.globalDefaults = {}; + /** polyfill to fix an issue in ie browser */ if (typeof NodeList !== 'undefined' && NodeList.prototype && !NodeList.prototype.forEach) { NodeList.prototype.forEach = Array.prototype.forEach; diff --git a/docs/assets/virtual-select.min.css b/docs/assets/virtual-select.min.css index 29fc53e..fb800b3 100644 --- a/docs/assets/virtual-select.min.css +++ b/docs/assets/virtual-select.min.css @@ -1,9 +1,9 @@ /*! - * Virtual Select v1.3.0 + * Virtual Select v1.4.0 * https://sa-si-dev.github.io/virtual-select * Licensed under MIT (https://github.com/sa-si-dev/virtual-select/blob/master/LICENSE) */ -@keyframes vscomp-animation-spin{to{transform:rotateZ(360deg)}}.vscomp-popup-active{overflow:hidden !important}.vscomp-ele{display:inline-block;max-width:250px;width:100%}.vscomp-wrapper{color:#333;display:inline-flex;flex-wrap:wrap;font-family:sans-serif;font-size:14px;position:relative;text-align:left;width:100%}.vscomp-wrapper *,.vscomp-wrapper *::before,.vscomp-wrapper *::after{box-sizing:border-box}.vscomp-wrapper:focus{outline:none}.vscomp-dropbox-wrapper{left:0;position:absolute;top:0}.vscomp-toggle-button{align-items:center;background-color:#fff;border:1px solid #ddd;cursor:pointer;display:flex;padding:7px 30px 7px 10px;position:relative;width:100%}.vscomp-value{height:20px;line-height:20px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vscomp-arrow{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;width:30px}.vscomp-arrow::after{transform:rotate(45deg);border:1px solid rgba(0,0,0,0);border-bottom-color:#111;border-right-color:#111;content:"";height:8px;margin-top:-6px;width:8px}.vscomp-clear-icon{height:12px;position:relative;width:12px}.vscomp-clear-icon::before,.vscomp-clear-icon::after{background-color:#999;content:"";height:12px;left:5px;position:absolute;top:0;width:2px}.vscomp-clear-icon::before{transform:rotate(45deg)}.vscomp-clear-icon::after{transform:rotate(-45deg)}.vscomp-clear-icon:hover::before,.vscomp-clear-icon:hover::after{background:#333}.vscomp-clear-button{align-items:center;border-radius:50%;display:none;height:24px;justify-content:center;margin-top:-12px;position:absolute;right:30px;top:50%;width:24px}.vscomp-clear-button:hover{background:#ccc}.vscomp-clear-button:hover .vscomp-clear-icon::before,.vscomp-clear-button:hover .vscomp-clear-icon::after{background-color:#333}.vscomp-dropbox-close-button{align-items:center;background-color:#fff;border-radius:50%;bottom:-48px;cursor:pointer;display:none;height:40px;justify-content:center;left:50%;margin-left:-20px;position:absolute;width:40px}.vscomp-value-tag.more-value-count{white-space:nowrap}.vscomp-dropbox-container{width:100%;z-index:2}.vscomp-dropbox{background-color:#fff;width:100%}.vscomp-options-container{max-height:210px;overflow:auto;position:relative}.vscomp-options-bottom-freezer{bottom:0;height:2px;left:0;position:absolute;right:0}.vscomp-option{align-items:center;cursor:pointer;display:flex;flex-wrap:wrap;height:40px;padding:0 15px;position:relative}.vscomp-option.selected{background-color:#eee}.vscomp-option.focused{background-color:#ccc}.vscomp-option.disabled{cursor:default;opacity:.5}.vscomp-option.group-title .vscomp-option-text{cursor:default;opacity:.6}.vscomp-option.group-title.selected{background-color:rgba(0,0,0,0)}.vscomp-option.group-option{padding-left:30px}.vscomp-new-option-icon{height:30px;position:absolute;right:0;top:0;width:30px}.vscomp-new-option-icon::before{border:15px solid #512da8;border-bottom-color:rgba(0,0,0,0);border-left-color:rgba(0,0,0,0);content:"";position:absolute;right:0;top:0}.vscomp-new-option-icon::after{align-items:center;color:#fff;content:"+";display:flex;font-size:18px;height:15px;justify-content:center;position:absolute;right:1px;top:0;width:15px}.vscomp-option-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;-webkit-user-select:none;user-select:none;width:100%}.vscomp-option-description{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#666;font-size:13px;line-height:15px;width:100%}.vscomp-search-container{align-items:center;border-bottom:1px solid #ddd;display:flex;height:40px;padding:0 5px 0 15px;position:relative}.vscomp-search-label,.vscomp-live-region,.vscomp-dropbox-container-top,.vscomp-dropbox-container-bottom{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.vscomp-search-input{background-color:rgba(0,0,0,0);border:0;color:inherit;font-size:15px;height:38px;padding:10px 0;width:calc(100% - 30px)}.vscomp-search-input:focus{outline:none}.vscomp-search-clear{align-items:center;color:#999;cursor:pointer;display:flex;font-size:25px;height:30px;justify-content:center;-webkit-user-select:none;user-select:none;visibility:hidden;width:30px}.vscomp-search-clear:hover{color:inherit}.vscomp-no-options,.vscomp-no-search-results{align-items:center;display:none;justify-content:center;padding:20px 10px}.vscomp-options-loader{display:none;padding:20px 0;text-align:center}.vscomp-options-loader::before{animation:vscomp-animation-spin .8s infinite linear;background-color:#fff;border-radius:50%;box-shadow:-4px -5px 3px -3px rgba(0,0,0,.3);content:"";display:inline-block;height:40px;opacity:.7;width:40px}.vscomp-ele[disabled]{cursor:not-allowed;-webkit-user-select:none;user-select:none}.vscomp-ele[disabled] .vscomp-wrapper{opacity:.7;pointer-events:none}.vscomp-wrapper .checkbox-icon{display:inline-flex;height:15px;margin-right:10px;position:relative;width:15px}.vscomp-wrapper .checkbox-icon::after{transition-duration:.2s;border:2px solid #888;content:"";display:inline-block;height:100%;width:100%}.vscomp-wrapper .checkbox-icon.checked::after{transform:rotate(45deg) translate(1px, -4px);border-color:#512da8;border-left-color:rgba(0,0,0,0);border-top-color:rgba(0,0,0,0);width:50%}.vscomp-wrapper.show-as-popup .vscomp-dropbox-container{align-items:center;background-color:rgba(0,0,0,.5);display:flex;height:100vh;justify-content:center;left:0;opacity:1;overflow:auto;padding:0 10px;position:fixed;top:0;width:100vw}.vscomp-wrapper.show-as-popup .vscomp-dropbox{margin-top:-24px;max-height:calc(80% - 48px);max-width:500px;position:relative;width:80%}.vscomp-wrapper.show-as-popup .vscomp-dropbox-close-button{display:flex}.vscomp-wrapper.popup-position-left .vscomp-dropbox-container{justify-content:flex-start}.vscomp-wrapper.popup-position-right .vscomp-dropbox-container{justify-content:flex-end}.vscomp-wrapper.has-select-all .vscomp-toggle-all-button{align-items:center;cursor:pointer;display:flex}.vscomp-wrapper.has-select-all .vscomp-search-input,.vscomp-wrapper.has-select-all .vscomp-toggle-all-label{width:calc(100% - 55px)}.vscomp-wrapper.has-select-all .vscomp-toggle-all-label{display:none}.vscomp-wrapper:not(.has-search-input) .vscomp-toggle-all-button{width:100%}.vscomp-wrapper:not(.has-search-input) .vscomp-toggle-all-label{display:inline-block}.vscomp-wrapper.multiple .vscomp-option .vscomp-option-text{width:calc(100% - 25px)}.vscomp-wrapper.multiple .vscomp-option .vscomp-option-description{padding-left:25px}.vscomp-wrapper.multiple .vscomp-option.selected .checkbox-icon::after{transform:rotate(45deg) translate(1px, -4px);border-color:#512da8;border-left-color:rgba(0,0,0,0);border-top-color:rgba(0,0,0,0);width:50%}.vscomp-wrapper.focused .vscomp-toggle-button,.vscomp-wrapper:focus .vscomp-toggle-button{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2)}.vscomp-wrapper.closed .vscomp-dropbox-container,.vscomp-wrapper.closed.vscomp-dropbox-wrapper{display:none}.vscomp-wrapper:not(.has-value) .vscomp-value{opacity:.5}.vscomp-wrapper.has-clear-button.has-value .vscomp-clear-button{display:flex}.vscomp-wrapper.has-clear-button .vscomp-toggle-button{padding-right:54px}.vscomp-wrapper.has-no-options .vscomp-options-container,.vscomp-wrapper.has-no-search-results .vscomp-options-container{display:none}.vscomp-wrapper.has-no-options .vscomp-no-options{display:flex}.vscomp-wrapper.has-no-search-results .vscomp-no-search-results{display:flex}.vscomp-wrapper.has-search-value .vscomp-search-clear{visibility:visible}.vscomp-wrapper.has-no-options .vscomp-toggle-all-button{opacity:.5;pointer-events:none}.vscomp-wrapper.keep-always-open .vscomp-toggle-button{padding-right:24px}.vscomp-wrapper.keep-always-open .vscomp-clear-button{right:5px}.vscomp-wrapper.keep-always-open .vscomp-arrow{display:none}.vscomp-wrapper.keep-always-open .vscomp-dropbox-container{position:relative;z-index:1}.vscomp-wrapper.keep-always-open .vscomp-dropbox{transition-duration:0s;border:1px solid #ddd;box-shadow:none}.vscomp-wrapper.keep-always-open.focused,.vscomp-wrapper.keep-always-open:focus,.vscomp-wrapper.keep-always-open:hover{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2)}.vscomp-wrapper.server-searching .vscomp-options-list{display:none}.vscomp-wrapper.server-searching .vscomp-options-loader{display:block}.vscomp-wrapper.has-error .vscomp-toggle-button{border-color:#b00020}.vscomp-wrapper.show-value-as-tags .vscomp-toggle-button{padding:4px 22px 0 10px}.vscomp-wrapper.show-value-as-tags .vscomp-value{display:flex;flex-wrap:wrap;height:auto;min-height:28px;overflow:auto;text-overflow:unset;white-space:normal}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;align-items:center;border:1px solid #ddd;border-radius:20px;display:inline-flex;font-size:12px;line-height:16px;margin:0 4px 4px 0;max-width:100%;padding:2px 3px 2px 8px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag.more-value-count{padding-right:8px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:calc(100% - 20px)}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-clear-button{align-items:center;display:flex;height:20px;justify-content:center;width:20px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-clear-button .vscomp-clear-icon{transform:scale(0.8)}.vscomp-wrapper.show-value-as-tags .vscomp-arrow{height:34px}.vscomp-wrapper.show-value-as-tags .vscomp-clear-button{margin-top:0;top:5px}.vscomp-wrapper.show-value-as-tags.has-value .vscomp-arrow{display:none}.vscomp-wrapper.show-value-as-tags.has-value .vscomp-clear-button{right:2px}.vscomp-wrapper.show-value-as-tags:not(.has-value) .vscomp-toggle-button{padding-bottom:2px}.vscomp-wrapper.show-value-as-tags:not(.has-value) .vscomp-value{align-items:center;padding-bottom:3px}.vscomp-wrapper.text-direction-rtl{direction:rtl}.vscomp-wrapper.text-direction-rtl .vscomp-toggle-button{padding:7px 10px 7px 30px}.vscomp-wrapper.text-direction-rtl .vscomp-arrow{left:0;right:auto}.vscomp-wrapper.text-direction-rtl .vscomp-clear-button{left:30px;right:auto !important}.vscomp-wrapper.text-direction-rtl .checkbox-icon{margin-left:10px;margin-right:0}.vscomp-wrapper.text-direction-rtl .checkbox-icon.checked::after{transform:rotate(45deg) translate(-4px, 1px)}.vscomp-wrapper.text-direction-rtl .vscomp-search-container{padding:0 15px 0 5px}.vscomp-wrapper.text-direction-rtl .vscomp-toggle-all-label{text-align:right}.vscomp-wrapper.text-direction-rtl .vscomp-option{text-align:right}.vscomp-wrapper.text-direction-rtl .vscomp-option.group-option{padding-right:30px}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon{left:0;right:auto}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon::before{border-left-color:#512da8;border-right-color:rgba(0,0,0,0)}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon::after{left:1px;right:auto}.vscomp-wrapper.text-direction-rtl.multiple .vscomp-option.selected .checkbox-icon::after{transform:rotate(45deg) translate(-4px, 1px)}.vscomp-wrapper.text-direction-rtl.has-clear-button .vscomp-toggle-button{padding-left:54px}.vscomp-wrapper.text-direction-rtl.keep-always-open .vscomp-toggle-button{padding-left:24px}.vscomp-wrapper.text-direction-rtl.keep-always-open .vscomp-clear-button{left:5px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-toggle-button{padding:4px 10px 0 22px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-value-tag{margin:0 0 4px 4px;padding:2px 8px 2px 3px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-value-tag.more-value-count{padding-left:8px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags.has-value .vscomp-clear-button{left:2px} +@keyframes vscomp-animation-spin{to{transform:rotateZ(360deg)}}.vscomp-popup-active{overflow:hidden !important}.vscomp-ele{display:inline-block;max-width:250px;width:100%}.vscomp-wrapper{color:#333;display:inline-flex;flex-wrap:wrap;font-family:sans-serif;font-size:14px;position:relative;text-align:left;width:100%}.vscomp-wrapper *,.vscomp-wrapper *::before,.vscomp-wrapper *::after{box-sizing:border-box}.vscomp-wrapper:focus{outline:none}.vscomp-dropbox-wrapper{left:0;position:absolute;top:0}.vscomp-toggle-button{align-items:center;background-color:#fff;border:1px solid #ddd;cursor:pointer;display:flex;padding:7px 30px 7px 10px;position:relative;width:100%}.vscomp-value{height:20px;line-height:20px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vscomp-arrow{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;width:30px}.vscomp-arrow::after{transform:rotate(45deg);border:1px solid rgba(0,0,0,0);border-bottom-color:#111;border-right-color:#111;content:"";height:8px;margin-top:-6px;width:8px}.vscomp-clear-icon{height:12px;position:relative;width:12px}.vscomp-clear-icon::before,.vscomp-clear-icon::after{background-color:#999;content:"";height:12px;left:5px;position:absolute;top:0;width:2px}.vscomp-clear-icon::before{transform:rotate(45deg)}.vscomp-clear-icon::after{transform:rotate(-45deg)}.vscomp-clear-icon:hover::before,.vscomp-clear-icon:hover::after{background:#333}.vscomp-clear-button{align-items:center;border-radius:50%;display:none;height:24px;justify-content:center;margin-top:-12px;position:absolute;right:30px;top:50%;width:24px}.vscomp-clear-button:hover{background:#ccc}.vscomp-clear-button:hover .vscomp-clear-icon::before,.vscomp-clear-button:hover .vscomp-clear-icon::after{background-color:#333}.vscomp-dropbox-close-button{align-items:center;background-color:#fff;border-radius:50%;bottom:-48px;cursor:pointer;display:none;height:40px;justify-content:center;left:50%;margin-left:-20px;position:absolute;width:40px}.vscomp-value-tag.more-value-count{white-space:nowrap}.vscomp-dropbox-container{width:100%;z-index:2}.vscomp-dropbox{background-color:#fff;width:100%}.vscomp-options-container{max-height:210px;overflow:auto;position:relative}.vscomp-options-bottom-freezer{bottom:0;height:2px;left:0;position:absolute;right:0}.vscomp-option{align-items:center;cursor:pointer;display:flex;flex-wrap:wrap;height:40px;padding:0 15px;position:relative}.vscomp-option.selected{background-color:#eee}.vscomp-option.focused{background-color:#ccc}.vscomp-option.disabled{cursor:default;opacity:.5}.vscomp-option.group-title .vscomp-option-text{cursor:default;opacity:.6}.vscomp-option.group-title.selected{background-color:rgba(0,0,0,0)}.vscomp-option.group-option{padding-left:30px}.vscomp-new-option-icon{height:30px;position:absolute;right:0;top:0;width:30px}.vscomp-new-option-icon::before{border:15px solid #512da8;border-bottom-color:rgba(0,0,0,0);border-left-color:rgba(0,0,0,0);content:"";position:absolute;right:0;top:0}.vscomp-new-option-icon::after{align-items:center;color:#fff;content:"+";display:flex;font-size:18px;height:15px;justify-content:center;position:absolute;right:1px;top:0;width:15px}.vscomp-option-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;-webkit-user-select:none;user-select:none;width:100%}.vscomp-option-description{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#666;font-size:13px;line-height:15px;width:100%}.vscomp-search-container{align-items:center;border-bottom:1px solid #ddd;display:flex;height:40px;padding:0 5px 0 15px;position:relative}.vscomp-search-label,.vscomp-live-region,.vscomp-dropbox-container-top,.vscomp-dropbox-container-bottom{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.vscomp-search-input{background-color:rgba(0,0,0,0);border:0;color:inherit;font-size:15px;height:38px;padding:10px 0;width:calc(100% - 30px)}.vscomp-search-input:focus{outline:none}.vscomp-search-clear{align-items:center;color:#999;cursor:pointer;display:flex;font-size:25px;height:30px;justify-content:center;-webkit-user-select:none;user-select:none;visibility:hidden;width:30px}.vscomp-search-clear:hover{color:inherit}.vscomp-error-message{align-items:flex-start;color:#b00020;display:none;font-size:13px;gap:4px;line-height:1.4;padding-top:4px;width:100%}.vscomp-error-message::before{content:"\26A0";flex:none;font-size:1.1em;line-height:1.2}.vscomp-no-options,.vscomp-no-search-results{align-items:center;display:none;justify-content:center;padding:20px 10px}.vscomp-options-loader{display:none;padding:20px 0;text-align:center}.vscomp-options-loader::before{animation:vscomp-animation-spin .8s infinite linear;background-color:#fff;border-radius:50%;box-shadow:-4px -5px 3px -3px rgba(0,0,0,.3);content:"";display:inline-block;height:40px;opacity:.7;width:40px}.vscomp-ele[disabled]{cursor:not-allowed;-webkit-user-select:none;user-select:none}.vscomp-ele[disabled] .vscomp-wrapper{opacity:.7;pointer-events:none}.vscomp-wrapper .checkbox-icon{display:inline-flex;height:15px;margin-right:10px;position:relative;width:15px}.vscomp-wrapper .checkbox-icon::after{transition-duration:.2s;border:2px solid #888;content:"";display:inline-block;height:100%;width:100%}.vscomp-wrapper .checkbox-icon.checked::after{transform:rotate(45deg) translate(1px, -4px);border-color:#512da8;border-left-color:rgba(0,0,0,0);border-top-color:rgba(0,0,0,0);width:50%}.vscomp-wrapper.show-as-popup .vscomp-dropbox-container{align-items:center;background-color:rgba(0,0,0,.5);display:flex;height:100vh;justify-content:center;left:0;opacity:1;overflow:auto;padding:0 10px;position:fixed;top:0;width:100vw}.vscomp-wrapper.show-as-popup .vscomp-dropbox{margin-top:-24px;max-height:calc(80% - 48px);max-width:500px;position:relative;width:80%}.vscomp-wrapper.show-as-popup .vscomp-dropbox-close-button{display:flex}.vscomp-wrapper.popup-position-left .vscomp-dropbox-container{justify-content:flex-start}.vscomp-wrapper.popup-position-right .vscomp-dropbox-container{justify-content:flex-end}.vscomp-wrapper.has-select-all .vscomp-toggle-all-button{align-items:center;cursor:pointer;display:flex;min-height:24px;min-width:24px}.vscomp-wrapper.has-select-all .vscomp-search-input,.vscomp-wrapper.has-select-all .vscomp-toggle-all-label{width:calc(100% - 55px)}.vscomp-wrapper.has-select-all .vscomp-toggle-all-label{display:none}.vscomp-wrapper:not(.has-search-input) .vscomp-toggle-all-button{width:100%}.vscomp-wrapper:not(.has-search-input) .vscomp-toggle-all-label{display:inline-block}.vscomp-wrapper.multiple .vscomp-option .vscomp-option-text{width:calc(100% - 25px)}.vscomp-wrapper.multiple .vscomp-option .vscomp-option-description{padding-left:25px}.vscomp-wrapper.multiple .vscomp-option.selected .checkbox-icon::after{transform:rotate(45deg) translate(1px, -4px);border-color:#512da8;border-left-color:rgba(0,0,0,0);border-top-color:rgba(0,0,0,0);width:50%}.vscomp-wrapper.focused .vscomp-toggle-button,.vscomp-wrapper:focus .vscomp-toggle-button{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2)}.vscomp-wrapper.closed .vscomp-dropbox-container,.vscomp-wrapper.closed.vscomp-dropbox-wrapper{display:none}.vscomp-wrapper:not(.has-value) .vscomp-value{opacity:.5}.vscomp-wrapper.has-clear-button.has-value .vscomp-clear-button{display:flex}.vscomp-wrapper.has-clear-button .vscomp-toggle-button{padding-right:54px}.vscomp-wrapper.has-no-options .vscomp-options-container,.vscomp-wrapper.has-no-search-results .vscomp-options-container{display:none}.vscomp-wrapper.has-no-options .vscomp-no-options{display:flex}.vscomp-wrapper.has-no-search-results .vscomp-no-search-results{display:flex}.vscomp-wrapper.has-search-value .vscomp-search-clear{visibility:visible}.vscomp-wrapper.has-no-options .vscomp-toggle-all-button{opacity:.5;pointer-events:none}.vscomp-wrapper.keep-always-open .vscomp-toggle-button{padding-right:24px}.vscomp-wrapper.keep-always-open .vscomp-clear-button{right:5px}.vscomp-wrapper.keep-always-open .vscomp-arrow{display:none}.vscomp-wrapper.keep-always-open .vscomp-dropbox-container{position:relative;z-index:1}.vscomp-wrapper.keep-always-open .vscomp-dropbox{transition-duration:0s;border:1px solid #ddd;box-shadow:none}.vscomp-wrapper.keep-always-open.focused,.vscomp-wrapper.keep-always-open:focus,.vscomp-wrapper.keep-always-open:hover{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12),0 1px 5px 0 rgba(0,0,0,.2)}.vscomp-wrapper.server-searching .vscomp-options-list{display:none}.vscomp-wrapper.server-searching .vscomp-options-loader{display:block}.vscomp-wrapper.has-error .vscomp-toggle-button{border-color:#b00020}.vscomp-wrapper.has-error~.vscomp-error-message{display:flex}.vscomp-wrapper.show-value-as-tags .vscomp-toggle-button{padding:4px 22px 0 10px}.vscomp-wrapper.show-value-as-tags .vscomp-value{display:flex;flex-wrap:wrap;height:auto;min-height:28px;overflow:auto;text-overflow:unset;white-space:normal}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;align-items:center;border:1px solid #ddd;border-radius:20px;display:inline-flex;font-size:12px;line-height:16px;margin:0 4px 4px 0;max-width:100%;padding:2px 3px 2px 8px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag.more-value-count{padding-right:8px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:calc(100% - 24px)}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-clear-button{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.vscomp-wrapper.show-value-as-tags .vscomp-value-tag-clear-button .vscomp-clear-icon{transform:scale(0.8)}.vscomp-wrapper.show-value-as-tags .vscomp-arrow{height:34px}.vscomp-wrapper.show-value-as-tags .vscomp-clear-button{margin-top:0;top:5px}.vscomp-wrapper.show-value-as-tags.has-value .vscomp-arrow{display:none}.vscomp-wrapper.show-value-as-tags.has-value .vscomp-clear-button{right:2px}.vscomp-wrapper.show-value-as-tags:not(.has-value) .vscomp-toggle-button{padding-bottom:2px}.vscomp-wrapper.show-value-as-tags:not(.has-value) .vscomp-value{align-items:center;padding-bottom:3px}@media(prefers-reduced-motion: reduce){.vscomp-dropbox-container,.vscomp-dropbox,.vscomp-wrapper .vscomp-toggle-button,.vscomp-dropbox-wrapper{transition-duration:0s !important}}.vscomp-wrapper.text-direction-rtl{direction:rtl}.vscomp-wrapper.text-direction-rtl .vscomp-toggle-button{padding:7px 10px 7px 30px}.vscomp-wrapper.text-direction-rtl .vscomp-arrow{left:0;right:auto}.vscomp-wrapper.text-direction-rtl .vscomp-clear-button{left:30px;right:auto !important}.vscomp-wrapper.text-direction-rtl .checkbox-icon{margin-left:10px;margin-right:0}.vscomp-wrapper.text-direction-rtl .checkbox-icon.checked::after{transform:rotate(45deg) translate(-4px, 1px)}.vscomp-wrapper.text-direction-rtl .vscomp-search-container{padding:0 15px 0 5px}.vscomp-wrapper.text-direction-rtl .vscomp-toggle-all-label{text-align:right}.vscomp-wrapper.text-direction-rtl .vscomp-option{text-align:right}.vscomp-wrapper.text-direction-rtl .vscomp-option.group-option{padding-right:30px}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon{left:0;right:auto}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon::before{border-left-color:#512da8;border-right-color:rgba(0,0,0,0)}.vscomp-wrapper.text-direction-rtl .vscomp-new-option-icon::after{left:1px;right:auto}.vscomp-wrapper.text-direction-rtl.multiple .vscomp-option.selected .checkbox-icon::after{transform:rotate(45deg) translate(-4px, 1px)}.vscomp-wrapper.text-direction-rtl.has-clear-button .vscomp-toggle-button{padding-left:54px}.vscomp-wrapper.text-direction-rtl.keep-always-open .vscomp-toggle-button{padding-left:24px}.vscomp-wrapper.text-direction-rtl.keep-always-open .vscomp-clear-button{left:5px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-toggle-button{padding:4px 10px 0 22px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-value-tag{margin:0 0 4px 4px;padding:2px 8px 2px 3px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags .vscomp-value-tag.more-value-count{padding-left:8px}.vscomp-wrapper.text-direction-rtl.show-value-as-tags.has-value .vscomp-clear-button{left:2px} /*! * Popover v1.0.13 * https://sa-si-dev.github.io/popover diff --git a/docs/assets/virtual-select.min.js b/docs/assets/virtual-select.min.js index 5ab3dec..d6ca8ea 100644 --- a/docs/assets/virtual-select.min.js +++ b/docs/assets/virtual-select.min.js @@ -1,5 +1,5 @@ /*! - * Virtual Select v1.3.0 + * Virtual Select v1.4.0 * https://sa-si-dev.github.io/virtual-select * Licensed under MIT (https://github.com/sa-si-dev/virtual-select/blob/master/LICENSE) - */!function(){"use strict";const e=/[^\p{L}\p{N}_]/gu;class t{static getString(e){return e||0===e?e.toString():""}static convertToBoolean(e,t=!1){let s;return s=!0===e||"true"===e||!1!==e&&"false"!==e&&t,s}static isEmpty(e){let t=!1;return e?Array.isArray(e)?0===e.length&&(t=!0):"object"==typeof e&&0===Object.keys(e).length&&(t=!0):t=!0,t}static isNotEmpty(e){return!t.isEmpty(e)}static normalizeValues(e){if(Array.isArray(e)){const t=new Array(e.length);for(let s=0;s!!e):[]}static getRandomInt(e,t=0){const s=Math.ceil(t),i=Math.floor(e);return Math.floor(Math.random()*(i-s-1))+s}static regexEscape(e){return e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}static normalizeString(t){return t.normalize("NFD").replace(e,"")}static willTextOverflow(e,t){const s=document.createElement("div");s.style.position="absolute",s.style.visibility="hidden",s.style.whiteSpace="nowrap",s.style.fontSize=window.getComputedStyle(e).fontSize,s.style.fontFamily=window.getComputedStyle(e).fontFamily,s.textContent=t,document.body.appendChild(s);const i=s.clientWidth;return document.body.removeChild(s),i>e.clientWidth}static replaceDoubleQuotesWithHTML(e){return e.replace(/"/g,""")}static containsHTML(e){return/<[a-z][\s\S]*>/i.test(e)}static containsHTMLorJS(e){return/<([a-z]+)[\s\S]*?>|on\w+="[^"]*"/i.test(e)}static sanitizeClassNames(e){return e?String(e).replace(/["<>]/g,""):e}static throttle(e,t){let s,i=null,o=[],n=0;function r(){const t=s,i=o;o=[],s=void 0,e.apply(t,i)}function a(...e){const a=Date.now(),l=t-(a-n);o=e,s=this,l<=0||l>t?(i&&(clearTimeout(i),i=null),n=a,r()):i||(i=setTimeout(()=>{n=Date.now(),i=null,r()},l))}return a.cancel=function(){i&&(clearTimeout(i),i=null),n=0,o=[],s=void 0},a}}class s{static addClass(e,t){if(!e)return;const i=t.split(" ");s.getElements(e).forEach(e=>{e.classList.add(...i)})}static removeClass(e,t){if(!e)return;const i=t.split(" ");s.getElements(e).forEach(e=>{e.classList.remove(...i)})}static toggleClass(e,t,i){if(!e)return;let o;void 0!==i&&(o=Boolean(i)),s.getElements(e).forEach(e=>{e.classList.toggle(t,o)})}static hasClass(e,t){return!!e&&e.classList.contains(t)}static hasEllipsis(e){return!!e&&e.scrollWidth>e.offsetWidth}static getData(e,t,s){if(!e)return;let i=e?e.dataset[t]:"";return"number"===s?i=parseFloat(i)||0:"true"===i?i=!0:"false"===i&&(i=!1),i}static setData(e,t,s){e&&(e.dataset[t]=s)}static setAttr(e,t,s){e&&e.setAttribute(t,s)}static setAttrFromEle(e,t,s,i){const o={};s.forEach(t=>{o[t]=e.getAttribute(t)}),s.forEach(e=>{const s=o[e];(s||-1!==i.indexOf(e)&&""===s)&&t.setAttribute(e,s)})}static setStyle(e,t,s){e&&(e.style[t]=s)}static setStyles(e,t){e&&t&&Object.keys(t).forEach(s=>{e.style[s]=t[s]})}static setAria(e,t,s){if(!e)return;let i=t;"role"!==i&&(i=`aria-${i}`),e.setAttribute(i,s)}static getElements(e){return e?void 0===e.forEach?[e]:e:[]}static getElementsBySelector(e="",t=void 0){let s;const i=void 0!==t?t:document;return""!==e&&(s=i.querySelectorAll(e)),void 0!==s?Array.from(s):[]}static addEvent(e,i,o,n){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{s.getElements(e).forEach(e=>{e.addEventListener(t,o,{capture:n})})})}static dispatchEvent(e,t,i=!1){if(!e)return;const o=s.getElements(e);setTimeout(()=>{o.forEach(e=>{e.dispatchEvent(new CustomEvent(t,{bubbles:i}))})},0)}static getAttributesText(e){let t="";return e?(Object.entries(e).forEach(([e,s])=>{void 0!==s&&(t+=` ${e}="${s}" `)}),t):t}static convertPropToDataAttr(e){return e?`data-${e}`.replace(/([A-Z])/g,"-$1").toLowerCase():""}static changeTabIndex(e,t){e?s.getElements(e).forEach(e=>{e.tabIndex=t}):console.log(e,"Invalid element provided.")}static removeEvent(e,t,i,o=!1){e&&s.getElements(e).forEach(e=>{e.removeEventListener(t,i,{capture:o})})}}const i={13:"onEnterPress",38:"onUpArrowPress",40:"onDownArrowPress",46:"onBackspaceOrDeletePress",8:"onBackspaceOrDeletePress"},o=["autofocus","disabled","multiple","required"],n=["autofocus","class","disabled","id","multiple","name","placeholder","required"];let r;const a=["additionalClasses","additionalDropboxClasses","additionalDropboxContainerClasses","additionalToggleButtonClasses","aliasKey","allOptionsSelectedText","allowNewOption","alwaysShowSelectedOptionsCount","alwaysShowSelectedOptionsLabel","ariaLabelledby","ariaLabelText","ariaLabelClearButtonText","ariaLabelTagClearButtonText","ariaLabelSearchClearButtonText","autoSelectFirstOption","clearButtonText","descriptionKey","disableAllOptionsSelectedText","disableOptionGroupCheckbox","disableSelectAll","disableValidation","dropboxWidth","dropboxWrapper","emptyValue","enableSecureText","focusSelectedOptionOnOpen","hasOptionDescription","hideClearButton","hideValueTooltipOnSelectAll","keepAlwaysOpen","labelKey","markSearchResults","maxValues","maxWidth","minValues","moreText","noOfDisplayValues","noOptionsText","noSearchResultsText","optionHeight","optionSelectedText","optionsCount","optionsSelectedText","popupDropboxBreakpoint","popupPosition","position","search","searchByStartsWith","searchDelay","searchFormLabel","searchGroup","searchNormalize","searchPlaceholderText","selectAllOnlyVisible","selectAllText","setValueAsArray","showDropboxAsPopup","showOptionsOnlyOnSearch","showSecureTextWarning","showSelectedOptionsFirst","showValueAsTags","silentInitialValueSet","textDirection","tooltipAlignment","tooltipFontSize","tooltipMaxWidth","updatePositionThrottle","useGroupValue","valueKey","zIndex"];class l{constructor(e){this.isDestroyed=!1;try{this.createSecureTextElements(),this.setProps(e),this.setDisabledOptions(e.disabledOptions),this.setOptions(e.options),this.warnIfSecureTextDisabled(),this.render()}catch(e){console.warn("Couldn't initiate Virtual Select"),console.error(e)}}render(){if(!this.$ele)return;const{uniqueId:e}=this;let i="vscomp-wrapper",o="vscomp-toggle-button";const n=this.showValueAsTags?"":this.getTooltipAttrText(this.placeholder,!0,!0),r=this.getTooltipAttrText(this.clearButtonText),a=this.ariaLabelledby?`aria-labelledby="${this.ariaLabelledby}"`:"",l=this.ariaLabelText?`aria-label="${this.ariaLabelText}"`:"",h=this.ariaLabelClearButtonText?`aria-label="${this.ariaLabelClearButtonText}"`:"";let p=!1;this.additionalClasses&&(i+=` ${t.sanitizeClassNames(this.additionalClasses)}`),this.additionalToggleButtonClasses&&(o+=` ${t.sanitizeClassNames(this.additionalToggleButtonClasses)}`),this.multiple&&(i+=" multiple",this.disableSelectAll||(i+=" has-select-all")),this.hideClearButton||(i+=" has-clear-button"),this.keepAlwaysOpen?(i+=" keep-always-open",p=!0):i+=" closed",this.showAsPopup&&(i+=" show-as-popup"),this.hasSearch&&(i+=" has-search-input"),this.showValueAsTags&&(i+=" show-value-as-tags"),this.textDirection&&(i+=` text-direction-${this.textDirection}`),this.popupPosition&&(i+=` popup-position-${this.popupPosition.toLowerCase()}`);const c=`
\n \n
\n
\n ${this.placeholder}\n
\n
\n
\n \n
\n
\n\n ${this.renderDropbox({wrapperClasses:i})}\n
`;this.$ele.innerHTML=c,this.$body=document.querySelector("body"),this.$wrapper=this.$ele.querySelector(".vscomp-wrapper"),this.hasDropboxWrapper?(this.$allWrappers=[this.$wrapper,this.$dropboxWrapper],this.$dropboxContainer=this.$dropboxWrapper.querySelector(".vscomp-dropbox-container"),s.addClass(this.$dropboxContainer,"pop-comp-wrapper")):(this.$allWrappers=[this.$wrapper],this.$dropboxContainer=this.$wrapper.querySelector(".vscomp-dropbox-container")),this.$toggleButton=this.$ele.querySelector(".vscomp-toggle-button"),this.$clearButton=this.$ele.querySelector(".vscomp-clear-button"),this.$valueText=this.$ele.querySelector(".vscomp-value"),this.$hiddenInput=this.$ele.querySelector(".vscomp-hidden-input"),this.$dropbox=this.$dropboxContainer.querySelector(".vscomp-dropbox"),this.$dropboxCloseButton=this.$dropboxContainer.querySelector(".vscomp-dropbox-close-button"),this.$dropboxContainerBottom=this.$dropboxContainer.querySelector(".vscomp-dropbox-container-bottom"),this.$dropboxContainerTop=this.$dropboxContainer.querySelector(".vscomp-dropbox-container-top"),this.$search=this.$dropboxContainer.querySelector(".vscomp-search-wrapper"),this.$optionsContainer=this.$dropboxContainer.querySelector(".vscomp-options-container"),this.$optionsList=this.$dropboxContainer.querySelector(".vscomp-options-list"),this.$options=this.$dropboxContainer.querySelector(".vscomp-options"),this.$noOptions=this.$dropboxContainer.querySelector(".vscomp-no-options"),this.$noSearchResults=this.$dropboxContainer.querySelector(".vscomp-no-search-results"),this.afterRenderWrapper()}renderDropbox({wrapperClasses:e}){const i="self"!==this.dropboxWrapper?document.querySelector(this.dropboxWrapper):null;let o="vscomp-dropbox";this.additionalDropboxClasses&&(o+=` ${t.sanitizeClassNames(this.additionalDropboxClasses)}`);let n="vscomp-dropbox-container";this.additionalDropboxContainerClasses&&(n+=` ${t.sanitizeClassNames(this.additionalDropboxContainerClasses)}`);const r=`
\n \n
\n
\n\n
\n
\n\n
\n
\n
\n
\n\n
\n
${this.noOptionsText}
\n
${this.noSearchResultsText}
\n\n \n
\n \n
`;if(i){const t=document.createElement("div");return this.$dropboxWrapper=t,this.hasDropboxWrapper=!0,t.innerHTML=r,i.appendChild(t),s.addClass(t,`vscomp-dropbox-wrapper ${e}`),this.keepAlwaysOpen||(s.setAttr(t,"tabindex","-1"),s.setAria(t,"hidden",!0)),""}return this.hasDropboxWrapper=!1,r}renderOptions(){this.calculateAriaMetadata();let e="";const s=this.getVisibleOptions();let i="",o="";const n=!(!this.markSearchResults||!this.searchValue);let r;const{labelRenderer:a,disableOptionGroupCheckbox:l,uniqueId:h,searchGroup:p}=this,c="function"==typeof a,{convertToBoolean:u}=t;let d="";if(n&&(r=new RegExp(`(${t.regexEscape(this.searchValue)})(?!([^<]+)?>)`,"gi")),this.multiple&&(i=''),this.allowNewOption){const e=this.getTooltipAttrText("New Option");o=``}s.forEach(s=>{const{index:v}=s;let b,m="vscomp-option";const f=this.getTooltipAttrText("",!0,!0);let g=i,S="",O="",x="",y="",$="-1";const w=u(s.isSelected);let C="";if(s.classNames&&(m+=` ${t.sanitizeClassNames(s.classNames)}`),s.isFocused&&($="0",m+=" focused"),s.isDisabled&&(m+=" disabled",C='aria-disabled="true"'),s.isGroupTitle&&(d=s.label,m+=" group-title",l?g="":this.multiple&&(y=`aria-label="${t.replaceDoubleQuotesWithHTML(t.getString(s.label))}, ${t.replaceDoubleQuotesWithHTML(t.getString(this.selectAllText))}"`)),w&&(m+=" selected"),s.isGroupOption){let e="";if(m+=" group-option",x=`data-group-index="${s.groupIndex}"`,s.customData){const i=this.secureText(t.getString(s.customData.group_name)),o=this.secureText(t.getString(s.customData.description));d=void 0!==s.customData.group_name?`${i}, `:"",e=void 0!==s.customData.description?` ${o},`:"",y=`aria-label="${d} ${s.label}, ${e}"`}else y=`aria-label="${d}, ${s.label}"`}b=c?a(s):s.label,s.description&&(O=`
${s.description}
`),s.isCurrentNew?(m+=" current-new",S+=o):!n||s.isGroupTitle&&!p||(b=b.replace(r,"$1"));let E="";this.ariaSetSize>0&&(E=`aria-setsize="${this.ariaSetSize}"`,s.filteredIndex&&(E+=` aria-posinset="${s.filteredIndex}"`)),e+=`
\n ${g}\n \n ${b}\n \n ${O}\n ${S}\n
`}),d="",this.$options.innerHTML=e,this.$visibleOptions=this.$options.querySelectorAll(".vscomp-option"),this.afterRenderOptions()}renderSearch(){if(!this.hasSearchContainer)return;let e="",t="";if(this.multiple&&!this.disableSelectAll&&(e=`\n \n ${this.selectAllText}\n `),this.hasSearch){const e=this.ariaLabelSearchClearButtonText?`aria-label="${this.ariaLabelSearchClearButtonText}"`:"";t=`\n \n ×`}const s=`
\n ${e}\n ${t}\n
`;this.$search.innerHTML=s,this.$searchInput=this.$dropboxContainer.querySelector(".vscomp-search-input"),this.$searchClear=this.$dropboxContainer.querySelector(".vscomp-search-clear"),this.$toggleAllButton=this.$dropboxContainer.querySelector(".vscomp-toggle-all-button"),this.$toggleAllCheckbox=this.$dropboxContainer.querySelector(".vscomp-toggle-all-checkbox"),this.addEvent(this.$searchInput,"input","onSearch"),this.addEvent(this.$searchInput,"change","preventPropagation"),this.addEvent(this.$searchClear,"click keydown","onSearchClear"),this.addEvent(this.$toggleAllButton,"click","onToggleAllOptions"),this.addEvent(this.$dropboxContainerBottom,"focus","onDropboxContainerTopOrBottomFocus"),this.addEvent(this.$dropboxContainerTop,"focus","onDropboxContainerTopOrBottomFocus")}addEvents(){this.addEvent(document,"click","onDocumentClick",!0),this.addEvent(this.$allWrappers,"keydown","onKeyDown"),this.addEvent(this.$toggleButton,"click keydown","onToggleButtonPress"),this.addEvent(this.$clearButton,"click keydown","onClearButtonClick"),this.addEvent(this.$dropboxContainer,"click","onDropboxContainerClick"),this.addEvent(this.$dropboxCloseButton,"click","onDropboxCloseButtonClick"),this.addEvent(this.$optionsContainer,"scroll","onOptionsScroll"),this.addEvent(this.$options,"click","onOptionsClick"),this.addEvent(this.$options,"mouseover","onOptionsMouseOver"),this.addEvent(this.$options,"touchmove","onOptionsTouchMove"),l.registerInstance(this)}addEvent(e,i,o,n=!1){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{const i=`${o}-${t}`;let r=this.events[i];r||(r=this[o].bind(this),this.events[i]=r),s.addEvent(e,t,r,n)})}removeEvents(){this.removeEvent(document,"click","onDocumentClick",!0),this.removeEvent(this.$allWrappers,"keydown","onKeyDown"),this.removeEvent(this.$toggleButton,"click keydown","onToggleButtonPress"),this.removeEvent(this.$clearButton,"click keydown","onClearButtonClick"),this.removeEvent(this.$dropboxContainer,"click","onDropboxContainerClick"),this.removeEvent(this.$dropboxCloseButton,"click","onDropboxCloseButtonClick"),this.removeEvent(this.$optionsContainer,"scroll","onOptionsScroll"),this.removeEvent(this.$options,"click","onOptionsClick"),this.removeEvent(this.$options,"mouseover","onOptionsMouseOver"),this.removeEvent(this.$options,"touchmove","onOptionsTouchMove"),this.$searchInput&&(this.removeEvent(this.$searchInput,"input","onSearch"),this.removeEvent(this.$searchInput,"change","preventPropagation"),this.$searchClear&&(this.removeEvent(this.$searchClear,"click","onSearchClear"),this.removeEvent(this.$searchClear,"keydown","onSearchClear"))),this.$toggleAllButton&&this.removeEvent(this.$toggleAllButton,"click","onToggleAllOptions"),this.$dropboxContainerBottom&&this.removeEvent(this.$dropboxContainerBottom,"focus","onDropboxContainerTopOrBottomFocus"),this.$dropboxContainerTop&&this.removeEvent(this.$dropboxContainerTop,"focus","onDropboxContainerTopOrBottomFocus")}removeEvent(e,i,o,n=!1){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{const i=`${o}-${t}`,r=this.events[i];r&&s.removeEvent(e,t,r,n)})}onDocumentClick(e){const t=e.target.closest(".vscomp-wrapper");if(!t)return void l.openInstances.forEach(e=>{const t=e;t.shouldFocusWrapperOnClose=!1,t.closeDropbox()});const s=t.parentElement.virtualSelect;s&&s!==this&&this.isOpened()&&!this.keepAlwaysOpen&&(this.shouldFocusWrapperOnClose=!1,this.closeDropbox())}onKeyDown(e){const t=e.which||e.keyCode,s=i[t];if(document.activeElement!==this.$searchInput||e.shiftKey||9!==t||this.multiple||(e.preventDefault(),this.focusFirstVisibleOption()),document.activeElement!==this.$toggleAllButton||13!==t){if(27===t||"Escape"===e.key){const e=this.showAsPopup?this.$wrapper:this.$dropboxWrapper;if(e&&(document.activeElement===e||e.contains(document.activeElement))&&!this.keepAlwaysOpen)return void this.closeDropbox()}s&&this[s](e)}else this.toggleAllOptions()}onEnterPress(e){e.preventDefault(),this.isOpened()?this.selectFocusedOption():!1===this.$ele.disabled&&this.openDropbox()}onDownArrowPress(e){document.activeElement!==this.$searchInput&&(e.preventDefault(),this.isOpened()?this.focusOption({direction:"next"}):this.openDropbox())}onUpArrowPress(e){document.activeElement!==this.$searchInput&&(e.preventDefault(),this.isOpened()?this.focusOption({direction:"previous"}):this.openDropbox())}onBackspaceOrDeletePress(e){e.target===this.$wrapper&&(e.preventDefault(),this.selectedValues.length>0&&this.reset())}onToggleButtonPress(e){if("keydown"===e.type){if("Enter"!==e.code&&"Space"!==e.code)return;e.preventDefault()}const t=e.target;if(t.closest(".vscomp-value-tag-clear-button"))return e.stopPropagation(),void this.removeValue(t.closest(".vscomp-value-tag"));t.closest(".toggle-button-child")||this.toggleDropbox()}onClearButtonClick(e){"click"===e.type?this.reset():"keydown"!==e.type||"Enter"!==e.code&&"Space"!==e.code||(e.stopPropagation(),this.reset())}onOptionsScroll(){this.setVisibleOptions(!0)}onOptionsClick(e){const t=e.target.closest(".vscomp-option");t&&!s.hasClass(t,"disabled")&&(s.hasClass(t,"group-title")?this.onGroupTitleClick(t):this.selectOption(t,{event:e}))}onGroupTitleClick(e){if(!e||!this.multiple||this.disableOptionGroupCheckbox)return;const t=!s.hasClass(e,"selected");this.toggleGroupTitleCheckbox(e,t),this.toggleGroupOptions(e,t)}onDropboxContainerClick(e){e.target.closest(".vscomp-dropbox")||this.closeDropbox()}onDropboxCloseButtonClick(){this.closeDropbox()}onOptionsMouseOver(e){const t=e.target.closest(".vscomp-option");t&&this.isOpened()&&(this.shouldSkipOptionInNavigation(t)?this.removeOptionFocus():this.focusOption({$option:t}))}onOptionsTouchMove(){this.removeOptionFocus()}onSearch(e){e.stopPropagation(),this.setSearchValue(e.target.value,!0)}preventPropagation(e){e.stopPropagation()}onSearchClear(e){e.stopPropagation(),"Enter"!==e.code&&"Space"!==e.code&&"click"!==e.type||(this.setSearchValue(""),this.focusSearchInput())}onToggleAllOptions(){this.toggleAllOptions()}onDropboxContainerTopOrBottomFocus(){this.closeDropbox()}onResize(){this.setOptionsContainerHeight(!0)}static observeDomChanges(){l.domObserver||(l.domObserver=new MutationObserver(e=>{e.forEach(e=>{e.removedNodes.forEach(e=>{if(e.nodeType!==Node.ELEMENT_NODE)return;const t=e.classList.contains("vscomp-ele")?[e]:[];e.querySelectorAll(".vscomp-ele").forEach(e=>t.push(e)),t.forEach(e=>{!e.isConnected&&e.virtualSelect&&e.virtualSelect.destroy()})})})}),l.domObserver.observe(document.documentElement,{childList:!0,subtree:!0}))}static disconnectDomObserver(){l.domObserver&&(l.domObserver.disconnect(),l.domObserver=null)}static addGlobalListeners(){l.hasGlobalListeners||(document.addEventListener("reset",l.onFormReset),document.addEventListener("submit",l.onFormSubmit),window.addEventListener("resize",l.onResizeThrottled),l.hasGlobalListeners=!0)}static removeGlobalListeners(){l.hasGlobalListeners&&(document.removeEventListener("reset",l.onFormReset),document.removeEventListener("submit",l.onFormSubmit),window.removeEventListener("resize",l.onResizeThrottled),l.onResizeThrottled&&"function"==typeof l.onResizeThrottled.cancel&&l.onResizeThrottled.cancel(),l.hasGlobalListeners=!1)}static registerInstance(e){l.activeInstances.add(e),l.addGlobalListeners(),l.observeDomChanges()}static unregisterInstance(e){l.activeInstances.delete(e),0===l.activeInstances.size&&(l.removeGlobalListeners(),l.disconnectDomObserver())}beforeValueSet(e){this.toggleAllOptionsClass(!e&&void 0)}beforeSelectNewValue(e){const t=this.getNewOption();if(t){const e=t.index;this.newValues.push(t.value),this.setOptionProp(e,"isCurrentNew",!1),this.setOptionProp(e,"isNew",!0)}else e&&(this.setNewOption(e),this.toggleSelectedProp(this.lastOptionIndex,!0));this.setManagedTimeout(()=>{this.setSearchValue(""),this.focusSearchInput()},0)}afterRenderWrapper(){s.addClass(this.$ele,"vscomp-ele"),this.renderSearch(),this.setEleStyles(),this.setDropboxStyles(),this.setVisibleOptionsCount(),this.setOptionsContainerHeight(),this.addEvents();try{this.setEleProps(),this.keepAlwaysOpen||this.showAsPopup||this.initDropboxPopover(),this.initialSelectedValue?this.setValueMethod(this.initialSelectedValue,this.silentInitialValueSet):this.autoSelectFirstOption&&this.visibleOptions.length&&this.setValueMethod(this.visibleOptions[0].value,this.silentInitialValueSet),this.showOptionsOnlyOnSearch&&this.setSearchValue("",!1,!0),this.initialDisabled&&this.disable(),this.autofocus&&this.focus()}catch(e){throw this.destroy(),e}}afterRenderOptions(){const e=this.getVisibleOptions(),t=!this.options.length&&!this.hasServerSearch,i=!t&&!e.length;(!this.allowNewOption||this.hasServerSearch||this.showOptionsOnlyOnSearch)&&(s.toggleClass(this.$allWrappers,"has-no-search-results",i),i?(s.setAttr(this.$noSearchResults,"tabindex","0"),s.setAttr(this.$noSearchResults,"aria-hidden","false")):(s.setAttr(this.$noSearchResults,"tabindex","-1"),s.setAttr(this.$noSearchResults,"aria-hidden","true"))),s.toggleClass(this.$allWrappers,"has-no-options",t),t?(s.setAttr(this.$noOptions,"tabindex","0"),s.setAttr(this.$noOptions,"aria-hidden","false")):(s.setAttr(this.$noOptions,"tabindex","-1"),s.setAttr(this.$noOptions,"aria-hidden","true")),this.setOptionAttr(),this.setOptionsPosition(),this.setOptionsTooltip(),document.activeElement!==this.$searchInput&&this.setManagedTimeout(()=>{const e=s.getElementsBySelector(".focused",this.$dropboxContainer)[0];void 0!==e&&e.focus({preventScroll:!0})},20)}afterSetOptionsContainerHeight(e){e&&this.showAsPopup&&this.setVisibleOptions()}afterSetSearchValue(){this.hasServerSearch?(clearTimeout(this.serverSearchTimeout),this.serverSearchTimeout=setTimeout(()=>{this.serverSearch()},this.searchDelay)):this.setVisibleOptionsCount(),this.selectAllOnlyVisible&&this.toggleAllOptionsClass(),this.focusOption({focusFirst:!0})}afterSetVisibleOptionsCount(){this.scrollToTop(),this.setOptionsHeight(),this.setVisibleOptions(),this.updatePosition()}afterValueSet(){this.scrollToTop(),this.setSearchValue(""),this.renderOptions()}afterSetOptions(e){e&&this.setSelectedProp(),this.setOptionsHeight(),this.setVisibleOptions(),this.showOptionsOnlyOnSearch&&this.setSearchValue("",!1,!0),e||this.reset()}setProps(e){const s=this.setDefaultProps(e);this.setPropsFromElementAttr(s);const{convertToBoolean:i}=t;this.$ele=s.ele,this.dropboxWrapper=s.dropboxWrapper,this.valueKey=s.valueKey,this.labelKey=s.labelKey,this.descriptionKey=s.descriptionKey,this.aliasKey=s.aliasKey,this.optionHeightText=s.optionHeight,this.optionHeight=parseFloat(this.optionHeightText),this.multiple=i(s.multiple),this.hasSearch=i(s.search),this.searchByStartsWith=i(s.searchByStartsWith),this.searchGroup=i(s.searchGroup),this.hideClearButton=i(s.hideClearButton),this.autoSelectFirstOption=i(s.autoSelectFirstOption),this.hasOptionDescription=i(s.hasOptionDescription),this.silentInitialValueSet=i(s.silentInitialValueSet),this.allowNewOption=i(s.allowNewOption),this.markSearchResults=i(s.markSearchResults),this.showSelectedOptionsFirst=i(s.showSelectedOptionsFirst),this.disableSelectAll=i(s.disableSelectAll),this.keepAlwaysOpen=i(s.keepAlwaysOpen),this.showDropboxAsPopup=i(s.showDropboxAsPopup),this.hideValueTooltipOnSelectAll=i(s.hideValueTooltipOnSelectAll),this.showOptionsOnlyOnSearch=i(s.showOptionsOnlyOnSearch),this.selectAllOnlyVisible=i(s.selectAllOnlyVisible),this.alwaysShowSelectedOptionsCount=i(s.alwaysShowSelectedOptionsCount),this.alwaysShowSelectedOptionsLabel=i(s.alwaysShowSelectedOptionsLabel),this.disableAllOptionsSelectedText=i(s.disableAllOptionsSelectedText),this.showValueAsTags=i(s.showValueAsTags),this.disableOptionGroupCheckbox=i(s.disableOptionGroupCheckbox),this.enableSecureText=i(s.enableSecureText),this.showSecureTextWarning=i(s.showSecureTextWarning,!0),this.setValueAsArray=i(s.setValueAsArray),this.disableValidation=i(s.disableValidation),this.initialDisabled=i(s.disabled),this.required=i(s.required),this.autofocus=i(s.autofocus),this.useGroupValue=i(s.useGroupValue),this.focusSelectedOptionOnOpen=i(s.focusSelectedOptionOnOpen),this.noOptionsText=s.noOptionsText,this.noSearchResultsText=s.noSearchResultsText,this.selectAllText=s.selectAllText,this.searchNormalize=s.searchNormalize,this.searchPlaceholderText=s.searchPlaceholderText,this.searchFormLabel=s.searchFormLabel,this.optionsSelectedText=s.optionsSelectedText,this.optionSelectedText=s.optionSelectedText,this.allOptionsSelectedText=s.allOptionsSelectedText,this.clearButtonText=s.clearButtonText,this.moreText=s.moreText,this.placeholder=s.placeholder,this.position=s.position,this.textDirection=s.textDirection,this.dropboxWidth=s.dropboxWidth,this.tooltipFontSize=s.tooltipFontSize,this.tooltipAlignment=s.tooltipAlignment,this.tooltipMaxWidth=s.tooltipMaxWidth,this.updatePositionThrottle=s.updatePositionThrottle,this.noOfDisplayValues=parseInt(s.noOfDisplayValues),this.zIndex=parseInt(s.zIndex),this.maxValues=parseInt(s.maxValues),this.minValues=parseInt(s.minValues),this.name=this.secureText(s.name),this.additionalClasses=s.additionalClasses,this.additionalDropboxClasses=s.additionalDropboxClasses,this.additionalDropboxContainerClasses=s.additionalDropboxContainerClasses,this.additionalToggleButtonClasses=s.additionalToggleButtonClasses,this.popupDropboxBreakpoint=s.popupDropboxBreakpoint,this.popupPosition=s.popupPosition,this.onServerSearch=s.onServerSearch,this.labelRenderer=s.labelRenderer,this.selectedLabelRenderer=s.selectedLabelRenderer,this.initialSelectedValue=0===s.selectedValue?"0":s.selectedValue,this.emptyValue=s.emptyValue,this.ariaLabelText=s.ariaLabelText,this.ariaLabelledby=s.ariaLabelledby,this.ariaLabelClearButtonText=s.ariaLabelClearButtonText,this.ariaLabelTagClearButtonText=s.ariaLabelTagClearButtonText,this.ariaLabelSearchClearButtonText=s.ariaLabelSearchClearButtonText,this.maxWidth=s.maxWidth,this.searchDelay=s.searchDelay,this.showDuration=parseInt(s.showDuration),this.hideDuration=parseInt(s.hideDuration),this.selectedValues=[],this.selectedOptions=[],this.newValues=[],this.events={},this.tooltipEnterDelay=200,this.searchValue="",this.searchValueOriginal="",this.isAllSelected=!1,(void 0===s.search&&this.multiple||this.allowNewOption||this.showOptionsOnlyOnSearch)&&(this.hasSearch=!0),this.hasServerSearch="function"==typeof this.onServerSearch,(this.maxValues||this.hasServerSearch||this.showOptionsOnlyOnSearch)&&(this.disableSelectAll=!0,this.disableOptionGroupCheckbox=!0),this.keepAlwaysOpen&&(this.dropboxWrapper="self"),this.showAsPopup=this.showDropboxAsPopup&&!this.keepAlwaysOpen&&window.innerWidth<=parseFloat(this.popupDropboxBreakpoint),this.hasSearchContainer=this.hasSearch||this.multiple&&!this.disableSelectAll,this.optionsCount=this.getOptionsCount(s.optionsCount),this.halfOptionsCount=Math.ceil(this.optionsCount/2),this.optionsHeight=this.getOptionsHeight(),this.uniqueId=this.getUniqueId(),this.shouldFocusWrapperOnClose=!0,this.ariaSetSize=0}setDefaultProps(e){const t={dropboxWrapper:"self",valueKey:"value",labelKey:"label",descriptionKey:"description",aliasKey:"alias",ariaLabelText:"Options list",ariaLabelClearButtonText:"Clear button",ariaLabelTagClearButtonText:"Remove option",ariaLabelSearchClearButtonText:"Clear search input",optionsCount:5,noOfDisplayValues:50,optionHeight:"40px",noOptionsText:"No options found",noSearchResultsText:"No results found",selectAllText:"Select All",searchNormalize:!1,searchPlaceholderText:"Search...",searchFormLabel:"Search",clearButtonText:"Clear",moreText:"more...",optionsSelectedText:"options selected",optionSelectedText:"option selected",allOptionsSelectedText:"All",placeholder:"Select",position:"bottom left",zIndex:e.keepAlwaysOpen?1:2,tooltipFontSize:"14px",tooltipAlignment:"center",tooltipMaxWidth:"300px",updatePositionThrottle:100,name:"",additionalClasses:"",additionalDropboxClasses:"",additionalDropboxContainerClasses:"",additionalToggleButtonClasses:"",maxValues:0,showDropboxAsPopup:!0,showSecureTextWarning:!0,popupDropboxBreakpoint:"576px",popupPosition:"center",hideValueTooltipOnSelectAll:!0,emptyValue:"",searchDelay:300,focusSelectedOptionOnOpen:!0,showDuration:300,hideDuration:200};return e.hasOptionDescription&&(t.optionsCount=4,t.optionHeight="50px"),Object.assign(t,e)}setPropsFromElementAttr(e){const t=e.ele;Object.keys(r).forEach(s=>{let i=t.getAttribute(s);-1===o.indexOf(s)||""!==i&&"true"!==i||(i=!0),i&&(e[r[s]]=i)})}setEleProps(){const{$ele:e}=this;e.virtualSelect=this,e.value=this.multiple?[]:"",e.name=this.name,e.disabled=!1,e.required=this.required,e.autofocus=this.autofocus,e.multiple=this.multiple,e.form=e.closest("form"),e.reset=l.reset,e.setValue=l.setValueMethod,e.setOptions=l.setOptionsMethod,e.setDisabledOptions=l.setDisabledOptionsMethod,e.setEnabledOptions=l.setEnabledOptionsMethod,e.toggleSelectAll=l.toggleSelectAll,e.isAllSelected=l.isAllSelected,e.addOption=l.addOptionMethod,e.getNewValue=l.getNewValueMethod,e.getDisplayValue=l.getDisplayValueMethod,e.getSelectedOptions=l.getSelectedOptionsMethod,e.getDisabledOptions=l.getDisabledOptionsMethod,e.open=l.openMethod,e.close=l.closeMethod,e.focus=l.focusMethod,e.enable=l.enableMethod,e.disable=l.disableMethod,e.destroy=l.destroyMethod,e.validate=l.validateMethod,e.toggleRequired=l.toggleRequiredMethod,this.hasDropboxWrapper&&(this.$dropboxWrapper.virtualSelect=this)}setValueMethod(e,s){const i={},o={};let n=[];const r=this.multiple;let a=t.normalizeValues(e);if(a){if(Array.isArray(a)||(a=[a]),r){const{maxValues:e}=this;e&&a.length>e&&a.splice(e)}else a.length>1&&(a=[a[0]]);this.useGroupValue&&(a=this.setGroupOptionsValue(a)),a.forEach((e,t)=>{i[e]=!0,o[e]=t}),this.allowNewOption&&a&&this.setNewOptionsFromValue(a)}this.options.forEach(e=>{const s=t.normalizeValues(e.value);!0!==i[s]||e.isDisabled||e.isGroupTitle?e.isSelected=!1:(e.isSelected=!0,n.push(e.value))}),r?(this.hasOptionGroup&&this.setGroupsSelectedProp(),n.sort((e,s)=>o[t.normalizeValues(e)]-o[t.normalizeValues(s)])):[n]=n,this.beforeValueSet(),this.setValue(n,{disableEvent:s}),this.afterValueSet()}setGroupOptionsValue(e){const t=[],s={},i={};return e.forEach(e=>{i[e]=!0}),this.options.forEach(e=>{const{value:o}=e,n=!0===i[o];e.isGroupTitle?n&&(s[e.index]=!0):(n||s[e.groupIndex])&&t.push(o)}),t}setGroupsSelectedProp(){const e=this.isAllGroupOptionsSelected.bind(this);this.options.forEach(t=>{t.isGroupTitle&&(t.isSelected=e(t.index))})}setOptionsMethod(e,t){this.setOptions(e),this.afterSetOptions(t)}setDisabledOptionsMethod(e,t=!1){this.setDisabledOptions(e,!0),t||(this.setValueMethod(null),this.toggleAllOptionsClass()),this.setVisibleOptions()}setDisabledOptions(e,t=!1){let s=[];if(e)if(!0===e)t&&this.options.forEach(e=>(e.isDisabled=!0,s.push(e.value),e));else{s=e.map(e=>e.toString());const i={};s.forEach(e=>{i[e]=!0}),t&&this.options.forEach(e=>(e.isDisabled=!0===i[e.value],e))}else t&&this.options.forEach(e=>(e.isDisabled=!1,e));this.disabledOptions=s}setEnabledOptionsMethod(e,t=!1){this.setEnabledOptions(e),t||(this.setValueMethod(null),this.toggleAllOptionsClass()),this.setVisibleOptions()}setEnabledOptions(e){if(void 0===e)return;const t=[];if(!0===e)this.options.forEach(e=>(e.isDisabled=!1,e));else{const s={};e.forEach(e=>{s[e]=!0}),this.options.forEach(e=>{const i=!0!==s[e.value];return e.isDisabled=i,i&&t.push(e.value),e})}this.disabledOptions=t}setOptions(e=[]){const s=[],i=this.disabledOptions.length,{valueKey:o,labelKey:n,descriptionKey:r,aliasKey:a,hasOptionDescription:l}=this,{getString:h,convertToBoolean:p}=t,c=this.secureText.bind(this),u=this.getAlias.bind(this);let d=0,v=!1;const b={};let m=!1;this.disabledOptions.forEach(e=>{b[e]=!0});const f=e=>{"object"!=typeof e&&(e={[o]:e,[n]:e});const g=c(h(e[o])),S=c(h(e[n])),O=e.options,x=!!O,y={index:d,value:g,valueNormalized:g.toLowerCase(),label:S,labelNormalized:this.searchNormalize&&""!==S.trim()?t.normalizeString(S).toLowerCase():S.toLowerCase(),alias:u(e[a]),isVisible:p(e.isVisible,!0),isNew:e.isNew||!1,isGroupTitle:x,classNames:e.classNames};if(m||""!==g||(m=!0),i&&(y.isDisabled=!0===b[g]),e.isGroupOption&&(y.isGroupOption=!0,y.groupIndex=e.groupIndex),l){const s=c(h(e[r]));y.description=s,y.descriptionNormalized=this.searchNormalize&&""!==s.trim()?t.normalizeString(s).toLowerCase():s.toLowerCase()}if(e.customData&&(y.customData=e.customData),s.push(y),d+=1,x){const e=y.index;v=!0,O.forEach(t=>{t.isGroupOption=!0,t.groupIndex=e,f(t)})}};Array.isArray(e)&&e.forEach(f);const g=s.length,{$ele:S}=this;S.options=s,S.length=g,this.options=s,this.visibleOptionsCount=g,this.lastOptionIndex=g-1,this.newValues=[],this.hasOptionGroup=v,this.hasEmptyValueOption=m,this.setSortedOptions()}setServerOptions(e=[]){this.setOptionsMethod(e,!0);const{selectedOptions:t}=this,i=this.options;let o=!1;if(t.length){const e={};o=!0,i.forEach(t=>{e[t.value]=!0}),t.forEach(t=>{!0!==e[t.value]&&(t.isVisible=!1,i.push(t))}),this.setOptionsMethod(i,!0)}this.allowNewOption&&this.searchValue&&(i.some(e=>e.label.toLowerCase()===this.searchValue)||(o=!0,this.setNewOption())),o?(this.setVisibleOptionsCount(),this.multiple&&this.toggleAllOptionsClass(),this.setValueText()):this.updatePosition(),this.setVisibleOptionsCount(),s.removeClass(this.$allWrappers,"server-searching")}setSelectedOptions(){this.selectedOptions=this.options.filter(e=>e.isSelected)}setSortedOptions(){let e=[...this.options];this.showSelectedOptionsFirst&&this.selectedValues.length&&(e=this.hasOptionGroup?this.sortOptionsGroup(e):this.sortOptions(e)),this.sortedOptions=e}setVisibleOptions(){let e=[...this.sortedOptions];const t=2*this.optionsCount,s=this.getVisibleStartIndex(),i=this.getNewOption(),o=s+t-1;let n=0;i&&(i.visibleIndex=n,n+=1),e=e.filter(e=>{let t=!1;return e.isVisible&&!e.isCurrentNew&&(t=n>=s&&n<=o,e.visibleIndex=n,n+=1),t}),i&&(e=[i,...e]),this.visibleOptions=e,this.visibleOptionsCount=e.length,this.renderOptions()}setOptionsPosition(e){const t=parseInt((e||this.getVisibleStartIndex())*this.optionHeight);this.$options.style.transform=`translate3d(0, ${t}px, 0)`,s.setData(this.$options,"top",t)}setOptionsTooltip(){const e=this.getVisibleOptions(),{hasOptionDescription:t}=this;e.forEach(e=>{const i=this.$dropboxContainer.querySelector(`.vscomp-option[data-index="${e.index}"]`);s.setData(i.querySelector(".vscomp-option-text"),"tooltip",e.label),t&&s.setData(i.querySelector(".vscomp-option-description"),"tooltip",e.description)})}setValue(e,{disableEvent:i=!1,disableValidation:o=!1}={}){const n=t.normalizeValues(e);this.hasEmptyValueOption&&""===n||n?Array.isArray(n)?this.selectedValues=[...n]:this.selectedValues=[n]:this.selectedValues=[];const r=this.getValue();this.$ele.value=r,this.$hiddenInput.value=this.getInputValue(r),this.isMaxValuesSelected=!!(this.maxValues&&this.maxValues<=this.selectedValues.length),this.toggleAllOptionsClass(),this.setValueText();const a=t.isNotEmpty(this.selectedValues);s.toggleClass(this.$allWrappers,"has-value",a),s.toggleClass(this.$allWrappers,"max-value-selected",this.isMaxValuesSelected),s.setAttr(this.$clearButton,"tabindex",a?"0":"-1"),s.setAria(this.$clearButton,"hidden",!1===a),o||this.validate(),i||s.dispatchEvent(this.$ele,"change",!0)}setValueText(){const{multiple:e,selectedValues:i,noOfDisplayValues:o,showValueAsTags:n,$valueText:r,selectedLabelRenderer:a}=this,l=[];let h=[];const p=i.length;let c=0;const u=this.isAllSelected&&!this.hasServerSearch&&!this.disableAllOptionsSelectedText&&!n;if(u&&this.hideValueTooltipOnSelectAll)r.innerHTML=`${this.allOptionsSelectedText} (${p})`;else{this.getSelectedOptions({fullDetails:!0,keepSelectionOrder:!0}).some(e=>{if(e.isCurrentNew)return!1;if(c>=o)return!0;let{label:s}=e;if("function"==typeof a&&(s=a(e)),l.push(s),c+=1,n){const i=t.willTextOverflow(r.parentElement,s)?this.getTooltipAttrText(s,!1,!0):"";let o="";this.ariaLabelTagClearButtonText&&(o=`aria-label="${s.replace(/<[^>]+>/gi,"").trim()}, ${this.ariaLabelTagClearButtonText}"`);const n=`\n ${s}\n \n \n \n `;h.push(n)}else h.push(s);return!1});const i=p-o;i>0&&h.push(`+ ${i} ${this.moreText}`);const d=l.join(", ");if(""===d)r.innerHTML=this.placeholder;else if(r.innerHTML=d,e){const{maxValues:e}=this;if(this.alwaysShowSelectedOptionsCount||s.hasEllipsis(r)||e||n){let t=`${p}`;if(e&&(t+=` / ${e}`),u)r.innerHTML=`${this.allOptionsSelectedText} (${p})`;else if(n)r.innerHTML=h.join(""),this.$valueTags=r.querySelectorAll(".vscomp-value-tag"),this.setValueTagAttr();else if(!this.alwaysShowSelectedOptionsLabel){const e=1===p?this.optionSelectedText:this.optionsSelectedText;r.innerHTML=`${t} ${e}`}}else h=[]}}let d="";0===p?d=this.placeholder:n||(d=h.join(", ")),n||s.setData(r,"tooltip",d),e&&(n?this.updatePosition():s.setData(r,"tooltipEllipsisOnly",0===p))}setSearchValue(e,t=!1,i=!1){if(e===this.searchValueOriginal&&!i)return;t||(this.$searchInput.value=e);const o=e.replace(/\\/g,"").toLowerCase().trim();this.searchValue=o,this.searchValueOriginal=e,s.toggleClass(this.$allWrappers,"has-search-value",e),s.setAttr(this.$searchClear,"tabindex",""!==e?"0":"-1"),s.setAria(this.$searchClear,"hidden",""===e),this.afterSetSearchValue()}setVisibleOptionsCount(){let e,s=0,i=!1;const{searchGroup:o,showOptionsOnlyOnSearch:n,searchByStartsWith:r}=this;let{searchValue:a}=this;a=this.searchNormalize&&""!==a.trim()?t.normalizeString(a):a;const l=this.isOptionVisible.bind(this);this.hasOptionGroup&&(e=this.getVisibleOptionGroupsMapping(a)),this.options.forEach(t=>{if(t.isCurrentNew)return;let h;n&&!a?(t.isVisible=!1,h={isVisible:!1,hasExactOption:!1}):h=l({data:t,searchValue:a,hasExactOption:i,visibleOptionGroupsMapping:e,searchGroup:o,searchByStartsWith:r}),h.isVisible&&(s+=1),i||(i=h.hasExactOption)}),this.allowNewOption&&(a&&!i?(this.setNewOption(),s+=1):this.removeNewOption()),this.visibleOptionsCount=s,this.afterSetVisibleOptionsCount()}calculateAriaMetadata(){let e=0,t=0;if((this.sortedOptions&&this.sortedOptions.length?this.sortedOptions:this.options).forEach(s=>{if(s.isCurrentNew)s.filteredIndex=void 0;else if(!0===s.isVisible){const i=s.isGroupTitle&&this.multiple&&!this.disableOptionGroupCheckbox;!s.isGroupTitle||i?(t+=1,e+=1,s.filteredIndex=t):s.filteredIndex=void 0}else s.filteredIndex=void 0}),this.allowNewOption){const s=this.getNewOption();s&&!0===s.isVisible?(t+=1,e+=1,s.filteredIndex=t):s&&(s.filteredIndex=void 0)}this.ariaSetSize=e}setOptionProp(e,t,s){this.options[e]&&(this.options[e][t]=s)}setOptionsHeight(){this.$optionsList.style.height=this.optionHeight*this.visibleOptionsCount+"px"}setOptionsContainerHeight(e){let t;e?this.showAsPopup&&(this.optionsCount=this.getOptionsCount(),this.halfOptionsCount=Math.ceil(this.optionsCount/2),t=this.getOptionsHeight(),this.optionsHeight=t):(t=this.optionsHeight,this.keepAlwaysOpen&&(s.setStyle(this.$noOptions,"height",t),s.setStyle(this.$noSearchResults,"height",t))),s.setStyle(this.$optionsContainer,"max-height",t),this.afterSetOptionsContainerHeight(e)}setNewOption(e){const t=e||this.searchValueOriginal.trim();if(!t)return;const s=this.getNewOption();if(s){const e=s.index;this.setOptionProp(e,"value",this.secureText(t)),this.setOptionProp(e,"label",this.secureText(t))}else{const s={value:t,label:t};e?(s.isNew=!0,this.newValues.push(t)):s.isCurrentNew=!0,this.addOption(s)}}setSelectedProp(){const e={};this.selectedValues.forEach(t=>{e[t]=!0}),this.options.forEach(t=>{!0===e[t.value]&&(t.isSelected=!0)})}setNewOptionsFromValue(e){if(!e)return;const t=this.setNewOption.bind(this),s={};this.options.forEach(e=>{s[e.value]=!0}),e.forEach(e=>{e&&!0!==s[e]&&t(e)})}setDropboxWrapperWidth(){if(this.showAsPopup)return;const e=this.dropboxWidth||`${this.$wrapper.offsetWidth}px`;s.setStyle(this.$dropboxContainer,"max-width",e)}setEleStyles(){const{maxWidth:e}=this,t={};e&&(t["max-width"]=e),s.setStyles(this.$ele,t)}setDropboxStyles(){const{dropboxWidth:e}=this,t={},i={"z-index":this.zIndex};e&&(this.showAsPopup?t["max-width"]=e:i.width=e),s.setStyles(this.$dropboxContainer,i),s.setStyles(this.$dropbox,t)}setOptionAttr(){const{$visibleOptions:e}=this,{options:t}=this,i=`${this.optionHeight}px`,{setStyle:o,getData:n,setData:r}=s;e&&e.length&&e.forEach(e=>{const s=t[n(e,"index")];o(e,"height",i),r(e,"value",s.value)})}setValueTagAttr(){const{$valueTags:e}=this;if(!e||!e.length)return;const{getData:t,setData:i}=s,{options:o}=this;e.forEach(e=>{const s=t(e,"index");if(void 0!==s){const t=o[s];i(e,"value",t.value)}})}setScrollTop(){const{selectedValues:e}=this;if(this.showSelectedOptionsFirst||!this.focusSelectedOptionOnOpen||0===e.length)return;const t={};let s;e.forEach(e=>{t[e]=!0}),this.options.some(e=>!!t[e.value]&&(s=e.visibleIndex,!0)),s&&(this.$optionsContainer.scrollTop=this.optionHeight*s)}getVisibleOptions(){return this.visibleOptions||[]}getValue(){let e;return e=this.multiple?this.useGroupValue?this.getGroupValue():this.selectedValues:this.selectedValues[0]||"",t.normalizeValues(e)}getGroupValue(){const e=[],t={};return this.options.forEach(s=>{if(!s.isSelected)return;const{value:i}=s;s.isGroupTitle?i&&(t[s.index]=!0,e.push(i)):!0!==t[s.groupIndex]&&e.push(i)}),e}getInputValue(e){let t=e;return t&&t.length?this.setValueAsArray&&this.multiple&&(t=JSON.stringify(t)):t=this.emptyValue,t}getFirstVisibleOptionIndex(){return Math.ceil(this.$optionsContainer.scrollTop/this.optionHeight)}getVisibleStartIndex(){let e=this.getFirstVisibleOptionIndex()-this.halfOptionsCount;return e<0&&(e=0),e}getTooltipAttrText(e,i=!1,o=!1){const n={"data-tooltip":(t.containsHTML(e)?t.replaceDoubleQuotesWithHTML(e):e)||"","data-tooltip-enter-delay":this.tooltipEnterDelay,"data-tooltip-z-index":this.zIndex,"data-tooltip-font-size":this.tooltipFontSize,"data-tooltip-alignment":this.tooltipAlignment,"data-tooltip-max-width":this.tooltipMaxWidth,"data-tooltip-ellipsis-only":i,"data-tooltip-allow-html":o};return s.getAttributesText(n)}getOptionObj(e){if(!e)return;const{getString:s}=t,i=this.secureText.bind(this),o=i(s(e.value)),n=i(s(e.label)),r=i(s(e.description));return{index:e.index,value:o,valueNormalized:o.toLowerCase(),label:n,labelNormalized:this.searchNormalize&&""!==n.trim()?t.normalizeString(n).toLowerCase():n.toLowerCase(),description:r,descriptionNormalized:this.searchNormalize&&""!==r.trim()?t.normalizeString(r).toLowerCase():r.toLowerCase(),alias:this.getAlias(e.alias),isCurrentNew:e.isCurrentNew||!1,isNew:e.isNew||!1,isVisible:!0}}getNewOption(){const e=this.options[this.lastOptionIndex];if(e&&e.isCurrentNew)return e}getOptionIndex(e){let t;return this.options.some(s=>s.value===e&&(t=s.index,!0)),t}getNewValue(){const e={};this.newValues.forEach(t=>{e[t]=!0});const t=this.selectedValues.filter(t=>!0===e[t]);return this.multiple?t:t[0]}getAlias(e){let t=e;return t&&(t=Array.isArray(t)?t.join(","):t.toString().trim(),t=t.toLowerCase()),t||""}getDisplayValue(){const e=[];return this.options.forEach(t=>{t.isSelected&&e.push(t.label)}),this.multiple?e:e[0]||""}getSelectedOptions({fullDetails:e=!1,keepSelectionOrder:t=!1}={}){const{valueKey:s,labelKey:i,selectedValues:o}=this,n=[];if(this.options.forEach(t=>{if(t.isSelected&&!t.isGroupTitle)if(e)n.push(t);else{const e={[s]:t.value,[i]:t.label};t.isNew&&(e.isNew=!0),t.customData&&(e.customData=t.customData),n.push(e)}}),t){const e={};o.forEach((t,s)=>{e[t]=s}),n.sort((t,s)=>e[t.value]-e[s.value])}return this.multiple||e?n:n[0]}getDisabledOptions(){const{valueKey:e,labelKey:t,disabledOptions:s}=this,i={},o=[];return s.forEach(e=>{i[e]=!0}),this.options.forEach(({value:s,label:n})=>{i[s]&&o.push({[e]:s,[t]:n})}),o}getVisibleOptionGroupsMapping(e){let{options:t}=this;const s={},i=this.isOptionVisible.bind(this);return t=this.structureOptionGroup(t),t.forEach(t=>{s[t.index]=t.options.some(t=>i({data:t,searchValue:e}).isVisible)}),s}getOptionsCount(e){let t;if(this.showAsPopup){let e=80*window.innerHeight/100-48;this.hasSearchContainer&&(e-=40),t=Math.floor(e/this.optionHeight)}else t=parseInt(e);return t}getOptionsHeight(){return this.optionsCount*this.optionHeight+"px"}isSelectableGroupTitle(e){return e&&s.hasClass(e,"group-title")&&this.multiple&&!this.disableOptionGroupCheckbox}shouldSkipOptionInNavigation(e){return!!e&&(!!s.hasClass(e,"disabled")||s.hasClass(e,"group-title")&&!this.isSelectableGroupTitle(e))}getSibling(e,t){const s="next"===t?"nextElementSibling":"previousElementSibling";let i=e;do{i&&(i=i[s])}while(this.shouldSkipOptionInNavigation(i));return i}getUniqueId(){const e=t.getRandomInt(1e4);return document.querySelector(`#vscomp-ele-wrapper-${e}`)?this.getUniqueId():e}initDropboxPopover(){const e={ele:this.$ele,target:this.$dropboxContainer,position:this.position,zIndex:this.zIndex,margin:4,transitionDistance:30,hideArrowIcon:!0,disableManualAction:!0,disableUpdatePosition:!this.hasDropboxWrapper,updatePositionThrottle:this.updatePositionThrottle,showDuration:this.showDuration,hideDuration:this.hideDuration,afterShow:this.afterShowPopper.bind(this),afterHide:this.afterHidePopper.bind(this)};this.dropboxPopover=new PopoverComponent(e)}openDropbox(e){l.lastInteractedInstance=this;let t="";e||(t=this.$dropboxContainer.style.transition,this.$dropboxContainer.style.transition="none"),this.isSilentOpen=e,l.openInstances.forEach(e=>{if(e!==this){const t=e;t.shouldFocusWrapperOnClose=!1,t.closeDropbox(!0)}}),l.openInstances.add(this),s.setAttr(this.$dropboxWrapper,"tabindex","0"),s.setAria(this.$dropboxWrapper,"hidden",!1),s.setAttr(this.$dropboxContainerTop,"tabindex","0"),s.setAria(this.$dropboxContainerTop,"hidden",!1),s.setAttr(this.$dropboxContainerBottom,"tabindex","0"),s.setAria(this.$dropboxContainerBottom,"hidden",!1),e?s.setStyle(this.$dropboxContainer,"display","inline-flex"):(s.dispatchEvent(this.$ele,"beforeOpen"),s.setAria(this.$wrapper,"expanded",!0)),this.setDropboxWrapperWidth(),s.removeClass(this.$allWrappers,"closed"),s.changeTabIndex(this.$allWrappers,0),e||(this.$dropboxContainer.offsetHeight,this.$dropboxContainer.style.transition=t),this.dropboxPopover&&!e?this.dropboxPopover.show():this.afterShowPopper()}afterShowPopper(){const e=this.isSilentOpen;this.isSilentOpen=!1,e||(this.moveSelectedOptionsFirst(),this.setScrollTop(),s.addClass(this.$allWrappers,"focused"),this.showAsPopup?(s.addClass(this.$body,"vscomp-popup-active"),this.isPopupActive=!0):this.focusElementOnOpen(),s.dispatchEvent(this.$ele,"afterOpen"))}closeDropbox(e){if(this.isSilentClose=e,l.openInstances.delete(this),!1===this.isOpened())return;if(this.keepAlwaysOpen)return void this.removeOptionFocus();const t=document.activeElement,i=t&&this.$wrapper.contains(t)||this.hasDropboxWrapper&&t&&this.$dropboxWrapper.contains(t);this.shouldFocusWrapperOnClose&&l.lastInteractedInstance===this&&!e&&(null===t||t===document.body||i)&&this.$wrapper.focus(),e?s.setStyle(this.$dropboxContainer,"display",""):(s.dispatchEvent(this.$ele,"beforeClose"),s.setAria(this.$wrapper,"expanded",!1),s.setAria(this.$wrapper,"activedescendant",""),s.setAria(this.$dropboxContainer,"activedescendant","")),this.dropboxPopover&&!e?(this.dropboxPopover.hide(),s.setAttr(this.$dropboxWrapper,"tabindex","-1"),s.setAria(this.$dropboxWrapper,"hidden",!0),s.setAttr(this.$dropboxContainerTop,"tabindex","-1"),s.setAria(this.$dropboxContainerTop,"hidden",!0),s.setAttr(this.$dropboxContainerBottom,"tabindex","-1"),s.setAria(this.$dropboxContainerBottom,"hidden",!0)):this.afterHidePopper(),this.setSearchValue("")}afterHidePopper(){const e=this.isSilentClose;this.isSilentClose=!1,s.removeClass(this.$allWrappers,"focused"),this.removeOptionFocus(),!e&&this.isPopupActive&&(s.removeClass(this.$body,"vscomp-popup-active"),this.isPopupActive=!1),s.addClass(this.$allWrappers,"closed"),e||s.dispatchEvent(this.$ele,"afterClose"),this.shouldFocusWrapperOnClose=!0,s.setAttr(this.$dropboxWrapper,"tabindex","-1"),s.setAria(this.$dropboxWrapper,"hidden",!0),s.setAttr(this.$dropboxContainerTop,"tabindex","-1"),s.setAria(this.$dropboxContainerTop,"hidden",!0),s.setAttr(this.$dropboxContainerBottom,"tabindex","-1"),s.setAria(this.$dropboxContainerBottom,"hidden",!0)}moveSelectedOptionsFirst(){this.$optionsContainer.scrollTop&&this.selectedValues.length||this.setVisibleOptions(),this.showSelectedOptionsFirst&&(this.setSortedOptions(),this.scrollToTop(),this.setVisibleOptions())}toggleDropbox(){l.lastInteractedInstance=this,this.isOpened()?this.closeDropbox():this.openDropbox()}updatePosition(){this.dropboxPopover&&this.isOpened()&&this.$ele.updatePosition()}isOpened(){return!s.hasClass(this.$wrapper,"closed")}focusSearchInput(){const e=this.$searchInput;e&&e.focus()}focusElementOnOpen(){const e=this.$searchInput,t=!this.options.length&&!this.hasServerSearch;if(e)t&&!this.allowNewOption?(s.setAttr(e,"disabled",""),this.$noOptions.focus()):(e.removeAttribute("disabled"),e.focus());else{const e=this.$dropbox.querySelector('[tabindex="0"]');void 0!==s.getData(e,"index")?this.focusOption({direction:"next"}):e?e.focus():this.focusFirstVisibleOption()}}focusFirstVisibleOption(){let e=this.$optionsContainer.querySelector(`[data-index='${this.getFirstVisibleOptionIndex()}']`);e?(this.shouldSkipOptionInNavigation(e)&&(e=this.getSibling(e,"next")),e&&(s.setAttr(e,"tabindex","0"),this.$optionsContainer.scrollTop=this.optionHeight*this.getFirstVisibleOptionIndex(),this.focusOption({focusFirst:!0}),e.focus())):(e=this.$dropbox.querySelector('[tabindex="0"]'),e&&e.focus())}focusOption({direction:e,$option:t,focusFirst:i}={}){const o=this.$dropboxContainer.querySelector(".vscomp-option.focused");let n;if(t)n=t;else if(!o||i){const e=this.getFirstVisibleOptionIndex();n=this.$dropboxContainer.querySelector(`.vscomp-option[data-visible-index="${e}"]`),this.shouldSkipOptionInNavigation(n)&&(n=this.getSibling(n,"next"))}else n=this.getSibling(o,e);n&&n!==o&&(o&&this.toggleOptionFocusedState(o,!1),this.toggleOptionFocusedState(n,!0),this.toggleFocusedProp(s.getData(n,"index"),!0),this.moveFocusedOptionToView(n))}moveFocusedOptionToView(e){const t=e||this.$dropboxContainer.querySelector(".vscomp-option.focused");if(!t)return;let i;const o=this.$optionsContainer.getBoundingClientRect(),n=t.getBoundingClientRect(),r=o.top,a=o.bottom,l=o.height,h=n.top,p=n.bottom,c=n.height,u=t.offsetTop,d=s.getData(this.$options,"top","number");r>h?i=u+d:a{if(e.isDisabled||e.isGroupTitle||!e.isVisible||e.isSelected)return;const{index:t}=e;if(t>o&&t{e(parseInt(t))})}this.setManagedTimeout(()=>{this.renderOptions()},0)}toggleAllOptions(e){if(!this.multiple||this.disableSelectAll)return;const t="boolean"==typeof isSelected?e:!s.hasClass(this.$toggleAllCheckbox,"checked"),i=[],{selectAllOnlyVisible:o}=this;this.options.forEach(e=>{const s=e;if(s.isDisabled||s.isCurrentNew)return;const{isVisible:n,isSelected:r}=s;!t&&(!o||n||!r)||t&&o&&!n&&!r?s.isSelected=!1:(s.isSelected=!0,s.isGroupTitle||i.push(s.value))}),this.toggleAllOptionsClass(t),this.setValue(i),this.renderOptions()}toggleAllOptionsClass(e){if(!this.multiple)return;let t=!1;"boolean"==typeof e||(e=this.isAllOptionsSelected()),!e&&this.selectAllOnlyVisible&&""!==this.searchValue&&(this.visibleOptionsCount>0||""===this.searchValue)&&(t=this.isAllOptionsSelected(!0)),s.toggleClass(this.$toggleAllCheckbox,"checked",e||t),this.isAllSelected=e}isAllOptionsSelected(e){let t=!1;return this.options.length&&this.selectedValues.length&&(t=!this.options.some(t=>!t.isSelected&&!t.isDisabled&&!t.isGroupTitle&&(!e||t.isVisible))),t}isAllGroupOptionsSelected(e){let t=!1;return this.options.length&&(t=!this.options.some(t=>!t.isSelected&&!t.isDisabled&&!t.isGroupTitle&&t.groupIndex===e)),t}toggleGroupOptionsParent(e,t){if(!this.hasOptionGroup||this.disableOptionGroupCheckbox||!e)return;let i=s.getData(e,"groupIndex");void 0!==i&&(i=parseInt(i));const o=this.$options.querySelector(`.vscomp-option[data-index="${i}"]`),n="boolean"==typeof t?t:this.isAllGroupOptionsSelected(i);this.toggleGroupTitleCheckbox(o,n),this.toggleGroupTitleProp(i,n)}toggleGroupTitleProp(e,t){const s="boolean"==typeof t?t:this.isAllGroupOptionsSelected(e);this.toggleSelectedProp(e,s)}toggleGroupOptions(e,i){if(!this.hasOptionGroup||this.disableOptionGroupCheckbox||!e)return;const o=s.getData(e,"index","number"),{selectedValues:n,selectAllOnlyVisible:r}=this,a={},{removeItemFromArray:l}=t;n.forEach(e=>{a[e]=!0}),this.options.forEach(e=>{if(e.isDisabled||e.groupIndex!==o)return;const{value:t}=e;!i||r&&!e.isVisible?(e.isSelected=!1,a[t]&&l(n,t)):(e.isSelected=!0,a[t]||n.push(t))}),this.toggleAllOptionsClass(!!i&&null),this.setValue(n),this.setManagedTimeout(()=>{this.renderOptions()},0)}toggleGroupTitleCheckbox(e,t){if(!e)return;const i=s.getData(e,"index","number");this.toggleSelectedProp(i,t),this.toggleOptionSelectedState(e,t)}toggleFocusedProp(e,t=!1){this.focusedOptionIndex&&this.setOptionProp(this.focusedOptionIndex,"isFocused",!1),this.setOptionProp(e,"isFocused",t),this.focusedOptionIndex=e}toggleSelectedProp(e,t=!1){this.setOptionProp(e,"isSelected",t)}scrollToTop(){const{scrollTop:e}=this.$optionsContainer;e>0&&(this.$optionsContainer.scrollTop=0)}reset(e=!1,t=!1){this.options.forEach(e=>{e.isSelected=!1}),this.beforeValueSet(!0),this.setValue(null,{disableEvent:t,disableValidation:e}),this.afterValueSet(),e&&s.removeClass(this.$allWrappers,"has-error"),s.dispatchEvent(this.$ele,"reset")}addOption(e,t){if(!e)return;this.lastOptionIndex+=1;const s=this.getOptionObj({...e,index:this.lastOptionIndex});this.options.push(s),this.sortedOptions.push(s),t&&(this.visibleOptionsCount+=1,this.afterSetOptions())}removeOption(e){(e||0===e)&&(this.options.splice(e,1),this.lastOptionIndex-=1)}removeNewOption(){const e=this.getNewOption();e&&this.removeOption(e.index)}sortOptions(e){return e.sort((e,t)=>{const s=e.isSelected||e.isAnySelected,i=t.isSelected||t.isAnySelected;return s||i?s&&(!i||e.index{const s=e.options;e.isAnySelected=s.some(e=>e.isSelected),e.isAnySelected&&t(s)}),t(s),this.destructureOptionGroup(s)}isOptionVisible({data:e,searchValue:s,hasExactOption:i,visibleOptionGroupsMapping:o,searchGroup:n,searchByStartsWith:r}){const a=null!=e.valueNormalized?e.valueNormalized:e.value.toLowerCase();let l=e.labelNormalized;if(null==l){const s=(e.label||"").trim();l=this.searchNormalize&&""!==s?t.normalizeString(s).toLowerCase():s.toLowerCase()}const{description:h,alias:p}=e;let{descriptionNormalized:c}=e;if(null==c){const e=h||"";c=this.searchNormalize&&""!==e.trim()?t.normalizeString(e).toLowerCase():e.toLowerCase()}let u=r?l.startsWith(s):l.includes(s);return!e.isGroupTitle||n&&u||(u=o[e.index]),r||!p||u||(u=p.includes(s)),r||!c||u||(u=c.includes(s)),e.isVisible=u,i||(i=l===s||a===s),{isVisible:u,hasExactOption:i}}structureOptionGroup(e){const t=[],s={};return e.forEach(e=>{if(e.isGroupTitle){const i=[];e.options=i,s[e.index]=i,t.push(e)}}),e.forEach(e=>{e.isGroupOption&&s[e.groupIndex].push(e)}),t}destructureOptionGroup(e){let t=[];return e.forEach(e=>{t.push(e),t=t.concat(e.options)}),t}serverSearch(){s.removeClass(this.$allWrappers,"has-no-search-results"),s.addClass(this.$allWrappers,"server-searching"),this.setSelectedOptions(),this.onServerSearch(this.searchValue,this)}removeValue(e){const{selectedValues:i}=this,o=s.getData(e,"value");t.removeItemFromArray(i,o),this.setValueMethod(i)}focus(){this.$wrapper.focus()}enable(){this.$ele.disabled=!1,this.$ele.removeAttribute("disabled"),this.$hiddenInput.removeAttribute("disabled"),s.setAria(this.$wrapper,"disabled",!1),s.changeTabIndex(this.$wrapper,0)}disable(){this.$ele.disabled=!0,this.$ele.setAttribute("disabled",""),this.$hiddenInput.setAttribute("disabled",""),s.setAria(this.$wrapper,"disabled",!0),s.changeTabIndex(this.$wrapper,-1),this.$wrapper.blur()}validate(){if(this.disableValidation)return!0;let e=!1;const{selectedValues:i,minValues:o}=this;return this.required&&(t.isEmpty(i)||this.multiple&&o&&i.length{this.managedTimeouts.delete(s),e()},t);return this.managedTimeouts.add(s),s}clearManagedTimeouts(){this.managedTimeouts&&(this.managedTimeouts.forEach(e=>clearTimeout(e)),this.managedTimeouts.clear())}destroy(){if(this.isDestroyed)return;this.isDestroyed=!0;const{$ele:e}=this;e.virtualSelect=void 0,e.value=void 0,e.innerHTML="",l.openInstances.delete(this),this===l.lastInteractedInstance&&(l.lastInteractedInstance=null),this.serverSearchTimeout&&(clearTimeout(this.serverSearchTimeout),this.serverSearchTimeout=null),this.clearManagedTimeouts(),this.removeEvents(),this.hasDropboxWrapper&&(this.$dropboxWrapper.virtualSelect=void 0,this.$dropboxWrapper.remove()),this.dropboxPopover&&this.dropboxPopover.destroy(),s.removeClass(e,"vscomp-ele"),this.events={},l.unregisterInstance(this)}createSecureTextElements(){this.$secureDiv=document.createElement("div"),this.$secureText=document.createTextNode(""),this.$secureDiv.appendChild(this.$secureText)}secureText(e){return e&&this.enableSecureText?(this.$secureText.nodeValue=t.replaceDoubleQuotesWithHTML(e),this.$secureDiv.innerHTML):e}warnIfSecureTextDisabled(){l.secureTextWarningShown||this.enableSecureText||!this.showSecureTextWarning||(l.secureTextWarningShown=!0,console.warn("[virtual-select] Option text (label, value, description) and any `customData` used in markup are rendered as HTML and are NOT escaped because `enableSecureText` is disabled (the default, kept off for performance on large datasets). If any option text can come from untrusted input, set `enableSecureText: true` to prevent XSS. Docs: https://sa-si-dev.github.io/virtual-select/#/properties"))}toggleRequired(e){this.required=t.convertToBoolean(e),this.$ele.required=this.required}toggleOptionSelectedState(e,t){let i=t;void 0===i&&(i=!s.hasClass(e,"selected")),s.toggleClass(e,"selected",i),s.setAria(e,"selected",i)}toggleOptionFocusedState(e,t){e&&(s.toggleClass(e,"focused",t),s.setAttr(e,"tabindex",t?"0":"-1"),document.activeElement!==this.$searchInput&&e.focus(),t&&(s.setAria(this.$wrapper,"activedescendant",e.id),s.setAria(this.$dropboxContainer,"activedescendant",e.id)))}static init(e){let t=e.ele;if(!t)return;let s=!1;if("string"==typeof t){t=document.querySelectorAll(t);const e=t.length;if(0===e)return;1===e&&(s=!0)}void 0!==t.length&&void 0!==t.forEach||(t=[t],s=!0);const i=[];return t.forEach(t=>{t.virtualSelect?i.push(t.virtualSelect):(e.ele=t,"SELECT"===t.tagName&&l.setPropsFromSelect(e),i.push(new l(e)))}),s?i[0]:i}static getAttrProps(){const{convertPropToDataAttr:e}=s,t={};return n.forEach(e=>{t[e]=e}),a.forEach(s=>{t[e(s)]=s}),t}static setPropsFromSelect(e){const t=e.ele,i=[],n=[],a=e=>{const t=[];return Array.from(e.children).forEach(e=>{const{value:s}=e,o={value:s};"OPTGROUP"===e.tagName?(o.label=e.getAttribute("label"),o.options=a(e)):o.label=e.innerHTML,t.push(o),e.disabled&&i.push(s),e.selected&&n.push(s)}),t},l=a(t),h=document.createElement("div");s.setAttrFromEle(t,h,Object.keys(r),o),t.parentNode.insertBefore(h,t),t.remove(),e.ele=h,e.options=l,e.disabledOptions=i,e.selectedValue=n}static onFormReset(e){const t=e.target.closest("form");t&&t.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{e.parentElement.virtualSelect.reset(!0)})}static onFormSubmit(e){l.validate(e.target.closest("form"))||e.preventDefault()}static validate(e){if(!e)return!0;let t=!1;return e.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{const s=e.parentElement.virtualSelect.validate();t||s||(t=!0)}),!t}static reset(e=!1,t=!1){this.virtualSelect.reset(e,t)}static setValueMethod(...e){this.virtualSelect.setValueMethod(...e)}static setOptionsMethod(...e){this.virtualSelect.setOptionsMethod(...e)}static setDisabledOptionsMethod(...e){this.virtualSelect.setDisabledOptionsMethod(...e)}static setEnabledOptionsMethod(...e){this.virtualSelect.setEnabledOptionsMethod(...e)}static toggleSelectAll(e){this.virtualSelect.toggleAllOptions(e)}static isAllSelected(){return this.virtualSelect.isAllSelected}static addOptionMethod(e){this.virtualSelect.addOption(e,!0)}static getNewValueMethod(){return this.virtualSelect.getNewValue()}static getDisplayValueMethod(){return this.virtualSelect.getDisplayValue()}static getSelectedOptionsMethod(e){return this.virtualSelect.getSelectedOptions(e)}static getDisabledOptionsMethod(){return this.virtualSelect.getDisabledOptions()}static openMethod(){return this.virtualSelect.openDropbox()}static closeMethod(){return this.virtualSelect.closeDropbox()}static focusMethod(){return this.virtualSelect.focus()}static enableMethod(){return this.virtualSelect.enable()}static disableMethod(){return this.virtualSelect.disable()}static destroyMethod(){return this.virtualSelect.destroy()}static validateMethod(){return this.virtualSelect.validate()}static toggleRequiredMethod(e){return this.virtualSelect.toggleRequired(e)}static onResizeMethod(){document.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{const t=e.parentElement&&e.parentElement.virtualSelect;t&&t.onResize()})}}l.onResizeThrottled=t.throttle(l.onResizeMethod,100),r=l.getAttrProps(),window.VirtualSelect=l,l.openInstances=new Set,l.domObserver=null,l.activeInstances=new Set,l.hasGlobalListeners=!1,l.lastInteractedInstance=null,l.secureTextWarningShown=!1,"undefined"!=typeof NodeList&&NodeList.prototype&&!NodeList.prototype.forEach&&(NodeList.prototype.forEach=Array.prototype.forEach)}(),function(){"use strict";function e(e){return function(e){if(Array.isArray(e))return t(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,s){if(e){if("string"==typeof e)return t(e,s);var i=Object.prototype.toString.call(e).slice(8,-1);return"Object"===i&&e.constructor&&(i=e.constructor.name),"Map"===i||"Set"===i?Array.from(e):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?t(e,s):void 0}}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function t(e,t){(null==t||t>e.length)&&(t=e.length);for(var s=0,i=new Array(t);ss-o-t.width?"left":"right",vertical:n>i-n-t.height?"top":"bottom"}}},{key:"getAbsoluteCoords",value:function(e){if(e){var t=e.getBoundingClientRect(),s=window.pageXOffset,i=window.pageYOffset;return{width:t.width,height:t.height,top:t.top+i,right:t.right+s,bottom:t.bottom+i,left:t.left+s}}}},{key:"getCoords",value:function(e){return e?e.getBoundingClientRect():{}}},{key:"getData",value:function(e,t,s){if(e){var i=e?e.dataset[t]:"";return"number"===s?i=parseFloat(i)||0:"true"===i?i=!0:"false"===i&&(i=!1),i}}},{key:"setData",value:function(e,t,s){e&&(e.dataset[t]=s)}},{key:"setStyle",value:function(e,t,s){e&&(e.style[t]=s)}},{key:"show",value:function(e){var s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"block";t.setStyle(e,"display",s)}},{key:"hide",value:function(e){t.setStyle(e,"display","none")}},{key:"getHideableParent",value:function(e){for(var t,s=e.parentElement;s;){var i=getComputedStyle(s).overflow;if(-1!==i.indexOf("scroll")||-1!==i.indexOf("auto")){t=s;break}s=s.parentElement}return t}}],s&&function(e,t){for(var s=0;sS?S-b:L:w+p>M&&("right"===E?n="left":w=M+bO?O-u:P:C+c>I&&("bottom"===E?n="top":C=I+up-j&&(G=p-j):"left"!==E&&"right"!==E||((H=f/2+g-R)c-j&&(H=c-j)),s.setStyle(this.$arrowEle,"transform","translate3d(".concat(parseInt(G),"px, ").concat(parseInt(H),"px, 0) ").concat(K))}s.hide(this.$popperEle)}},{key:"resetPosition",value:function(){s.setStyle(this.$popperEle,"transform","none"),this.setPosition()}},{key:"show",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},i=t.resetPosition,o=t.data;clearTimeout(this.exitDelayTimeout),clearTimeout(this.hideDurationTimeout),i&&this.resetPosition(),this.enterDelayTimeout=setTimeout(function(){var t=s.getData(e.$popperEle,"left"),i=s.getData(e.$popperEle,"top"),n="translate3d(".concat(parseInt(t),"px, ").concat(parseInt(i),"px, 0)"),r=e.showDuration;s.show(e.$popperEle,"inline-flex"),s.getCoords(e.$popperEle),s.setStyle(e.$popperEle,"transitionDuration",r+"ms"),s.setStyle(e.$popperEle,"transform",n),s.setStyle(e.$popperEle,"opacity",1),e.showDurationTimeout=setTimeout(function(){"function"==typeof e.afterShowCallback&&e.afterShowCallback(o)},r)},this.enterDelay)}},{key:"hide",value:function(){var e=this,t=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).data;clearTimeout(this.enterDelayTimeout),clearTimeout(this.showDurationTimeout),this.exitDelayTimeout=setTimeout(function(){if(e.$popperEle){var i=parseInt(s.getData(e.$popperEle,"fromLeft")),o=parseInt(s.getData(e.$popperEle,"fromTop")),n="translate3d(".concat(i,"px, ").concat(o,"px, 0)"),r=e.hideDuration;s.setStyle(e.$popperEle,"transitionDuration",r+"ms"),s.setStyle(e.$popperEle,"transform",n),s.setStyle(e.$popperEle,"opacity",0),e.hideDurationTimeout=setTimeout(function(){s.hide(e.$popperEle),"function"==typeof e.afterHideCallback&&e.afterHideCallback(t)},r)}},this.exitDelay)}},{key:"updatePosition",value:function(){s.setStyle(this.$popperEle,"transitionDuration","0ms"),this.resetPosition();var e=parseInt(s.getData(this.$popperEle,"left")),t=parseInt(s.getData(this.$popperEle,"top"));s.show(this.$popperEle,"inline-flex"),s.setStyle(this.$popperEle,"transform","translate3d(".concat(e,"px, ").concat(t,"px, 0)"))}}],t&&function(e,t){for(var s=0;s1&&void 0!==arguments[1]&&arguments[1]}},{key:"removeArrayEmpty",value:function(e){return Array.isArray(e)&&e.length?e.filter(function(e){return!!e}):[]}},{key:"throttle",value:function(e,t){var s,i=0;return function(){for(var o=arguments.length,n=new Array(o),r=0;re.length)&&(t=e.length);for(var s=0,i=new Array(t);s'),e=this.$popover.querySelector(".pop-comp-arrow")),this.$arrowEle=e}}},{key:"destroy",value:function(){this.removeEvents()}}])&&c(t.prototype,s),o&&c(t,o),Object.defineProperty(t,"prototype",{writable:!1}),t;var t,s,o}();d=m.getAttrProps(),window.PopoverComponent=m}(); + */!function(){"use strict";const e=/[^\p{L}\p{N}_]/gu;class t{static getString(e){return e||0===e?e.toString():""}static convertToBoolean(e,t=!1){let s;return s=!0===e||"true"===e||!1!==e&&"false"!==e&&t,s}static isEmpty(e){let t=!1;return e?Array.isArray(e)?0===e.length&&(t=!0):"object"==typeof e&&0===Object.keys(e).length&&(t=!0):t=!0,t}static isNotEmpty(e){return!t.isEmpty(e)}static normalizeValues(e){if(Array.isArray(e)){const t=new Array(e.length);for(let s=0;s!!e):[]}static getRandomInt(e,t=0){const s=Math.ceil(t),i=Math.floor(e);return Math.floor(Math.random()*(i-s-1))+s}static regexEscape(e){return e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}static normalizeString(t){return t.normalize("NFD").replace(e,"")}static prefersReducedMotion(){return"function"==typeof window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}static replaceDoubleQuotesWithHTML(e){return e.replace(/"/g,""")}static escapeAttributeValue(e){return t.getString(e).replace(/&/g,"&").replace(/"/g,""")}static decodeSecureText(e){return t.getString(e).replace(/</g,"<").replace(/>/g,">").replace(/ /g," ").replace(/&/g,"&")}static getPlainText(e){return t.decodeSecureText(e).replace(/<[^>]+>/gi," ").replace(/\s+/g," ").trim()}static getAriaLabelText(e){return t.escapeAttributeValue(t.getPlainText(e))}static containsHTML(e){return/<[a-z][\s\S]*>/i.test(e)}static containsHTMLorJS(e){return/<([a-z]+)[\s\S]*?>|on\w+="[^"]*"/i.test(e)}static sanitizeClassNames(e){return e?String(e).replace(/["<>]/g,""):e}static throttle(e,t){let s,i=null,o=[],n=0;function r(){const t=s,i=o;o=[],s=void 0,e.apply(t,i)}function a(...e){const a=Date.now(),l=t-(a-n);o=e,s=this,l<=0||l>t?(i&&(clearTimeout(i),i=null),n=a,r()):i||(i=setTimeout(()=>{n=Date.now(),i=null,r()},l))}return a.cancel=function(){i&&(clearTimeout(i),i=null),n=0,o=[],s=void 0},a}}class s{static addClass(e,t){if(!e)return;const i=t.split(" ");s.getElements(e).forEach(e=>{e.classList.add(...i)})}static removeClass(e,t){if(!e)return;const i=t.split(" ");s.getElements(e).forEach(e=>{e.classList.remove(...i)})}static toggleClass(e,t,i){if(!e)return;let o;void 0!==i&&(o=Boolean(i)),s.getElements(e).forEach(e=>{e.classList.toggle(t,o)})}static hasClass(e,t){return!!e&&e.classList.contains(t)}static hasEllipsis(e){return!!e&&e.scrollWidth>e.offsetWidth}static getData(e,t,s){if(!e)return;let i=e?e.dataset[t]:"";return"number"===s?i=parseFloat(i)||0:"true"===i?i=!0:"false"===i&&(i=!1),i}static setData(e,t,s){e&&(e.dataset[t]=s)}static setAttr(e,t,s){e&&e.setAttribute(t,s)}static removeAttr(e,t){e&&e.removeAttribute(t)}static toggleAria(e,t,i,o="true"){e&&s.getElements(e).forEach(e=>{i?e.setAttribute(`aria-${t}`,o):e.removeAttribute(`aria-${t}`)})}static setAttrFromEle(e,t,s,i){const o={};s.forEach(t=>{o[t]=e.getAttribute(t)}),s.forEach(e=>{const s=o[e];(s||-1!==i.indexOf(e)&&""===s)&&t.setAttribute(e,s)})}static setStyle(e,t,s){e&&(e.style[t]=s)}static setStyles(e,t){e&&t&&Object.keys(t).forEach(s=>{e.style[s]=t[s]})}static setAria(e,t,s){if(!e)return;let i=t;"role"!==i&&(i=`aria-${i}`),e.setAttribute(i,s)}static getElements(e){return e?void 0===e.forEach?[e]:e:[]}static getElementsBySelector(e="",t=void 0){let s;const i=void 0!==t?t:document;return""!==e&&(s=i.querySelectorAll(e)),void 0!==s?Array.from(s):[]}static addEvent(e,i,o,n){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{s.getElements(e).forEach(e=>{e.addEventListener(t,o,{capture:n})})})}static dispatchEvent(e,t,i=!1){if(!e)return;const o=s.getElements(e);setTimeout(()=>{o.forEach(e=>{e.dispatchEvent(new CustomEvent(t,{bubbles:i}))})},0)}static getAttributesText(e){let s="";return e?(Object.entries(e).forEach(([e,i])=>{void 0!==i&&(s+=` ${e}="${t.replaceDoubleQuotesWithHTML(String(i))}" `)}),s):s}static convertPropToDataAttr(e){return e?`data-${e}`.replace(/([A-Z])/g,"-$1").toLowerCase():""}static changeTabIndex(e,t){e?s.getElements(e).forEach(e=>{e.tabIndex=t}):console.log(e,"Invalid element provided.")}static removeEvent(e,t,i,o=!1){e&&s.getElements(e).forEach(e=>{e.removeEventListener(t,i,{capture:o})})}}const i={13:"onEnterPress",38:"onUpArrowPress",40:"onDownArrowPress",46:"onBackspaceOrDeletePress",8:"onBackspaceOrDeletePress"},o=["autofocus","disabled","multiple","required"],n=["autofocus","class","disabled","id","multiple","name","placeholder","required"];let r;const a=["additionalClasses","additionalDropboxClasses","additionalDropboxContainerClasses","additionalToggleButtonClasses","aliasKey","allOptionsSelectedText","allowNewOption","alwaysShowSelectedOptionsCount","alwaysShowSelectedOptionsLabel","ariaLabelledby","ariaLabelText","ariaLabelClearButtonText","ariaLabelTagClearButtonText","ariaLabelSearchClearButtonText","autoSelectFirstOption","clearButtonText","descriptionKey","disableAllOptionsSelectedText","disableOptionGroupCheckbox","disableSelectAll","disableValidation","dropboxWidth","dropboxWrapper","emptyValue","enableSecureText","focusSelectedOptionOnOpen","hasOptionDescription","hideClearButton","hideValueTooltipOnSelectAll","keepAlwaysOpen","labelKey","markSearchResults","maxValues","maxWidth","minValues","loadingText","minValuesErrorText","moreText","noOfDisplayValues","noOptionsSelectedText","noOptionsText","noSearchResultsText","optionHeight","optionSelectedText","optionsCount","optionsSelectedText","popupDropboxBreakpoint","popupPosition","position","requiredErrorText","search","searchByStartsWith","searchDelay","searchFormLabel","searchGroup","searchNormalize","searchPlaceholderText","searchResultText","searchResultsText","selectAllOnlyVisible","selectAllText","selectedText","setValueAsArray","showDropboxAsPopup","showOptionsOnlyOnSearch","showSecureTextWarning","showSelectedOptionsFirst","showValueAsTags","silentInitialValueSet","textDirection","tooltipAlignment","tooltipFontSize","tooltipMaxWidth","updatePositionThrottle","useGroupValue","valueKey","zIndex"];class l{constructor(e){this.isDestroyed=!1;try{this.createSecureTextElements(),this.setProps(e),this.setDisabledOptions(e.disabledOptions),this.setOptions(e.options),this.warnIfSecureTextDisabled(),this.render()}catch(e){console.warn("Couldn't initiate Virtual Select"),console.error(e)}}render(){if(!this.$ele)return;const{uniqueId:e}=this;let i="vscomp-wrapper",o="vscomp-toggle-button";const n=this.showValueAsTags?"":this.getTooltipAttrText(this.placeholder,!0,!0),r=this.getTooltipAttrText(this.clearButtonText),a=this.ariaLabelledby?`aria-labelledby="${t.replaceDoubleQuotesWithHTML(t.getString(this.ariaLabelledby))}"`:"",l=this.ariaLabelText?`aria-label="${t.getAriaLabelText(this.ariaLabelText)}"`:"",h=this.ariaLabelClearButtonText?`aria-label="${t.getAriaLabelText(this.ariaLabelClearButtonText)}"`:"";let p=!1;this.additionalClasses&&(i+=` ${t.sanitizeClassNames(this.additionalClasses)}`),this.additionalToggleButtonClasses&&(o+=` ${t.sanitizeClassNames(this.additionalToggleButtonClasses)}`),this.multiple&&(i+=" multiple",this.disableSelectAll||(i+=" has-select-all")),this.hideClearButton||(i+=" has-clear-button"),this.keepAlwaysOpen?(i+=" keep-always-open",p=!0):i+=" closed",this.showAsPopup&&(i+=" show-as-popup"),this.hasSearch&&(i+=" has-search-input"),this.showValueAsTags&&(i+=" show-value-as-tags"),this.textDirection&&(i+=` text-direction-${this.textDirection}`),this.popupPosition&&(i+=` popup-position-${this.popupPosition.toLowerCase()}`);const c=`
\n \n
\n
\n ${this.placeholder}\n
\n
\n
\n \n
\n
\n\n ${this.renderDropbox({wrapperClasses:i})}\n
\n\n
\n\n
`;this.$ele.innerHTML=c,this.$body=document.querySelector("body"),this.$wrapper=this.$ele.querySelector(".vscomp-wrapper"),this.hasDropboxWrapper?(this.$allWrappers=[this.$wrapper,this.$dropboxWrapper],this.$dropboxContainer=this.$dropboxWrapper.querySelector(".vscomp-dropbox-container"),s.addClass(this.$dropboxContainer,"pop-comp-wrapper")):(this.$allWrappers=[this.$wrapper],this.$dropboxContainer=this.$wrapper.querySelector(".vscomp-dropbox-container")),this.$toggleButton=this.$ele.querySelector(".vscomp-toggle-button"),this.$clearButton=this.$ele.querySelector(".vscomp-clear-button"),this.$valueText=this.$ele.querySelector(".vscomp-value"),this.$hiddenInput=this.$ele.querySelector(".vscomp-hidden-input"),this.$hiddenInput.name=this.name,this.$liveRegion=this.$ele.querySelector(".vscomp-live-region"),this.$errorMessage=this.$ele.querySelector(".vscomp-error-message"),this.$dropbox=this.$dropboxContainer.querySelector(".vscomp-dropbox"),this.$dropboxCloseButton=this.$dropboxContainer.querySelector(".vscomp-dropbox-close-button"),this.$dropboxContainerBottom=this.$dropboxContainer.querySelector(".vscomp-dropbox-container-bottom"),this.$dropboxContainerTop=this.$dropboxContainer.querySelector(".vscomp-dropbox-container-top"),this.$search=this.$dropboxContainer.querySelector(".vscomp-search-wrapper"),this.$optionsContainer=this.$dropboxContainer.querySelector(".vscomp-options-container"),this.$optionsList=this.$dropboxContainer.querySelector(".vscomp-options-list"),this.$options=this.$dropboxContainer.querySelector(".vscomp-options"),this.$noOptions=this.$dropboxContainer.querySelector(".vscomp-no-options"),this.$noSearchResults=this.$dropboxContainer.querySelector(".vscomp-no-search-results"),this.afterRenderWrapper()}renderDropbox({wrapperClasses:e}){const i="self"!==this.dropboxWrapper?document.querySelector(this.dropboxWrapper):null;let o="vscomp-dropbox";this.additionalDropboxClasses&&(o+=` ${t.sanitizeClassNames(this.additionalDropboxClasses)}`);let n="vscomp-dropbox-container";this.additionalDropboxContainerClasses&&(n+=` ${t.sanitizeClassNames(this.additionalDropboxContainerClasses)}`);const r=`
\n \n
\n
\n\n
\n
\n\n
\n
\n
\n
\n\n
\n
${this.noOptionsText}
\n
${this.noSearchResultsText}
\n\n \n
\n \n
`;if(i){const t=document.createElement("div");return this.$dropboxWrapper=t,this.hasDropboxWrapper=!0,t.innerHTML=r,i.appendChild(t),s.addClass(t,`vscomp-dropbox-wrapper ${e}`),this.keepAlwaysOpen||(s.setAttr(t,"tabindex","-1"),s.setAria(t,"hidden",!0)),""}return this.hasDropboxWrapper=!1,r}renderOptions(){this.ariaMetadataDirty&&(this.calculateAriaMetadata(),this.ariaMetadataDirty=!1);let e="";const s=this.getVisibleOptions();let i="",o="";const n=!(!this.markSearchResults||!this.searchValue);let r;const{labelRenderer:a,disableOptionGroupCheckbox:l,uniqueId:h,searchGroup:p}=this,c="function"==typeof a,{convertToBoolean:u}=t;let d="";if(n&&(r=new RegExp(`(${t.regexEscape(this.searchValue)})(?!([^<]+)?>)`,"gi")),this.multiple&&(i=''),this.allowNewOption){const e=this.getTooltipAttrText("New Option");o=``}s.forEach(s=>{const{index:v}=s;let b,m="vscomp-option";const g=this.getTooltipAttrText("",!0,!0);let f=i,x="",S="",O="",y="",$="-1";const w=u(s.isSelected);let C="";if(s.classNames&&(m+=` ${t.sanitizeClassNames(s.classNames)}`),s.isFocused&&($="0",m+=" focused"),s.isDisabled&&(m+=" disabled",C='aria-disabled="true"'),s.isGroupTitle)if(d=t.getAriaLabelText(s.label),m+=" group-title",l)f="";else if(this.multiple){const e=t.getAriaLabelText(this.selectAllText);y=`aria-label="${d}, ${e}"`}if(w&&(m+=" selected"),s.isGroupOption)if(m+=" group-option",O=`data-group-index="${s.groupIndex}"`,s.customData){const e=t.getAriaLabelText(this.secureText(t.getString(s.customData.group_name))),i=t.getAriaLabelText(this.secureText(t.getString(s.customData.description)));d=void 0!==s.customData.group_name?`${e}, `:"";const o=void 0!==s.customData.description?` ${i},`:"";y=`aria-label="${d} ${t.getAriaLabelText(s.label)}, ${o}"`}else y=`aria-label="${d}, ${t.getAriaLabelText(s.label)}"`;b=c?a(s):s.label,s.description&&(S=`
${s.description}
`),s.isCurrentNew?(m+=" current-new",x+=o):!n||s.isGroupTitle&&!p||(b=b.replace(r,"$1"));let T="";this.ariaSetSize>0&&(T=`aria-setsize="${this.ariaSetSize}"`,s.filteredIndex&&(T+=` aria-posinset="${s.filteredIndex}"`));const E=t.escapeAttributeValue(s.value);e+=`
\n ${f}\n \n ${b}\n \n ${S}\n ${x}\n
`}),d="",this.$options.innerHTML=e,this.$visibleOptions=this.$options.querySelectorAll(".vscomp-option"),this.afterRenderOptions()}renderSearch(){if(!this.hasSearchContainer)return;let e="",s="";if(this.multiple&&!this.disableSelectAll&&(e=`\n \n ${this.selectAllText}\n `),this.hasSearch){const e=this.ariaLabelSearchClearButtonText?`aria-label="${t.getAriaLabelText(this.ariaLabelSearchClearButtonText)}"`:"";s=`\n \n ×`}const i=`
\n ${e}\n ${s}\n
`;this.$search.innerHTML=i,this.$searchInput=this.$dropboxContainer.querySelector(".vscomp-search-input"),this.$searchClear=this.$dropboxContainer.querySelector(".vscomp-search-clear"),this.$toggleAllButton=this.$dropboxContainer.querySelector(".vscomp-toggle-all-button"),this.$toggleAllCheckbox=this.$dropboxContainer.querySelector(".vscomp-toggle-all-checkbox"),this.addEvent(this.$searchInput,"input","onSearch"),this.addEvent(this.$searchInput,"change","preventPropagation"),this.addEvent(this.$searchClear,"click keydown","onSearchClear"),this.addEvent(this.$toggleAllButton,"click","onToggleAllOptions"),this.addEvent(this.$dropboxContainerBottom,"focus","onDropboxContainerTopOrBottomFocus"),this.addEvent(this.$dropboxContainerTop,"focus","onDropboxContainerTopOrBottomFocus")}addEvents(){this.addEvent(document,"click","onDocumentClick",!0),this.addEvent(this.$allWrappers,"keydown","onKeyDown"),this.addEvent(this.$toggleButton,"click keydown","onToggleButtonPress"),this.addEvent(this.$clearButton,"click keydown","onClearButtonClick"),this.addEvent(this.$dropboxContainer,"click","onDropboxContainerClick"),this.addEvent(this.$dropboxCloseButton,"click","onDropboxCloseButtonClick"),this.addEvent(this.$optionsContainer,"scroll","onOptionsScroll"),this.addEvent(this.$options,"click","onOptionsClick"),this.addEvent(this.$options,"mouseover","onOptionsMouseOver"),this.addEvent(this.$options,"touchmove","onOptionsTouchMove"),l.registerInstance(this)}addEvent(e,i,o,n=!1){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{const i=`${o}-${t}`;let r=this.events[i];r||(r=this[o].bind(this),this.events[i]=r),s.addEvent(e,t,r,n)})}removeEvents(){this.removeEvent(document,"click","onDocumentClick",!0),this.removeEvent(this.$allWrappers,"keydown","onKeyDown"),this.removeEvent(this.$toggleButton,"click keydown","onToggleButtonPress"),this.removeEvent(this.$clearButton,"click keydown","onClearButtonClick"),this.removeEvent(this.$dropboxContainer,"click","onDropboxContainerClick"),this.removeEvent(this.$dropboxCloseButton,"click","onDropboxCloseButtonClick"),this.removeEvent(this.$optionsContainer,"scroll","onOptionsScroll"),this.removeEvent(this.$options,"click","onOptionsClick"),this.removeEvent(this.$options,"mouseover","onOptionsMouseOver"),this.removeEvent(this.$options,"touchmove","onOptionsTouchMove"),this.$searchInput&&(this.removeEvent(this.$searchInput,"input","onSearch"),this.removeEvent(this.$searchInput,"change","preventPropagation"),this.$searchClear&&(this.removeEvent(this.$searchClear,"click","onSearchClear"),this.removeEvent(this.$searchClear,"keydown","onSearchClear"))),this.$toggleAllButton&&this.removeEvent(this.$toggleAllButton,"click","onToggleAllOptions"),this.$dropboxContainerBottom&&this.removeEvent(this.$dropboxContainerBottom,"focus","onDropboxContainerTopOrBottomFocus"),this.$dropboxContainerTop&&this.removeEvent(this.$dropboxContainerTop,"focus","onDropboxContainerTopOrBottomFocus")}removeEvent(e,i,o,n=!1){e&&t.removeArrayEmpty(i.split(" ")).forEach(t=>{const i=`${o}-${t}`,r=this.events[i];r&&s.removeEvent(e,t,r,n)})}onDocumentClick(e){const t=e.target.closest(".vscomp-wrapper");if(!t)return void l.openInstances.forEach(e=>{const t=e;t.shouldFocusWrapperOnClose=!1,t.closeDropbox()});const s=t.parentElement.virtualSelect;s&&s!==this&&this.isOpened()&&!this.keepAlwaysOpen&&(this.shouldFocusWrapperOnClose=!1,this.closeDropbox())}onKeyDown(e){const t=e.which||e.keyCode,s=i[t];if(document.activeElement!==this.$searchInput||e.shiftKey||9!==t||this.multiple||(e.preventDefault(),this.focusFirstVisibleOption()),document.activeElement===this.$toggleAllButton&&(13===t||32===t))return e.preventDefault(),void this.toggleAllOptions();if(27===t||"Escape"===e.key){const e=this.hasDropboxWrapper&&!this.showAsPopup?this.$dropboxWrapper:this.$wrapper;if(e&&(document.activeElement===e||e.contains(document.activeElement))&&!this.keepAlwaysOpen)return void this.closeDropbox()}s&&this[s](e)}onEnterPress(e){e.preventDefault(),this.isOpened()?this.selectFocusedOption():!1===this.$ele.disabled&&this.openDropbox()}navigateOptions(e,t){e.preventDefault(),this.isOpened()?this.focusOption({direction:t}):this.openDropbox()}onDownArrowPress(e){this.navigateOptions(e,"next")}onUpArrowPress(e){this.navigateOptions(e,"previous")}onBackspaceOrDeletePress(e){e.target===this.$wrapper&&(e.preventDefault(),this.selectedValues.length>0&&this.reset())}onToggleButtonPress(e){if("keydown"===e.type){if("Enter"!==e.code&&"Space"!==e.code)return;e.preventDefault()}const t=e.target;if(t.closest(".vscomp-value-tag-clear-button"))return e.stopPropagation(),void this.removeValue(t.closest(".vscomp-value-tag"));t.closest(".toggle-button-child")||this.toggleDropbox()}onClearButtonClick(e){"click"===e.type?this.reset():"keydown"!==e.type||"Enter"!==e.code&&"Space"!==e.code||(e.stopPropagation(),this.reset())}onOptionsScroll(){this.scrollAnimationFrame||(this.scrollAnimationFrame=requestAnimationFrame(()=>{this.scrollAnimationFrame=null,this.isDestroyed||this.setVisibleOptions(!0)}))}onOptionsClick(e){const t=e.target.closest(".vscomp-option");t&&!s.hasClass(t,"disabled")&&(s.hasClass(t,"group-title")?this.onGroupTitleClick(t):this.selectOption(t,{event:e}))}onGroupTitleClick(e){if(!e||!this.multiple||this.disableOptionGroupCheckbox)return;const t=!s.hasClass(e,"selected");this.toggleGroupTitleCheckbox(e,t),this.toggleGroupOptions(e,t)}onDropboxContainerClick(e){e.target.closest(".vscomp-dropbox")||this.closeDropbox()}onDropboxCloseButtonClick(){this.closeDropbox()}onOptionsMouseOver(e){const t=e.target.closest(".vscomp-option");t&&this.isOpened()&&(this.shouldSkipOptionInNavigation(t)?this.removeOptionFocus():this.focusOption({$option:t}))}onOptionsTouchMove(){this.removeOptionFocus()}onSearch(e){e.stopPropagation(),this.setSearchValue(e.target.value,!0)}preventPropagation(e){e.stopPropagation()}onSearchClear(e){e.stopPropagation(),"Enter"!==e.code&&"Space"!==e.code&&"click"!==e.type||(this.setSearchValue(""),this.focusSearchInput())}onToggleAllOptions(){this.toggleAllOptions()}onDropboxContainerTopOrBottomFocus(){this.closeDropbox()}onResize(){this.setOptionsContainerHeight(!0)}static observeDomChanges(){l.domObserver||(l.domObserver=new MutationObserver(e=>{e.forEach(e=>{e.removedNodes.forEach(e=>{if(e.nodeType!==Node.ELEMENT_NODE)return;const t=e.classList.contains("vscomp-ele")?[e]:[];e.querySelectorAll(".vscomp-ele").forEach(e=>t.push(e)),t.forEach(e=>{!e.isConnected&&e.virtualSelect&&e.virtualSelect.destroy()})})})}),l.domObserver.observe(document.documentElement,{childList:!0,subtree:!0}))}static disconnectDomObserver(){l.domObserver&&(l.domObserver.disconnect(),l.domObserver=null)}static addGlobalListeners(){l.hasGlobalListeners||(document.addEventListener("reset",l.onFormReset),document.addEventListener("submit",l.onFormSubmit),window.addEventListener("resize",l.onResizeThrottled),l.hasGlobalListeners=!0)}static removeGlobalListeners(){l.hasGlobalListeners&&(document.removeEventListener("reset",l.onFormReset),document.removeEventListener("submit",l.onFormSubmit),window.removeEventListener("resize",l.onResizeThrottled),l.onResizeThrottled&&"function"==typeof l.onResizeThrottled.cancel&&l.onResizeThrottled.cancel(),l.hasGlobalListeners=!1)}static registerInstance(e){l.activeInstances.add(e),l.addGlobalListeners(),l.observeDomChanges()}static unregisterInstance(e){l.activeInstances.delete(e),0===l.activeInstances.size&&(l.removeGlobalListeners(),l.disconnectDomObserver())}beforeValueSet(e){this.toggleAllOptionsClass(!e&&void 0)}beforeSelectNewValue(e){const t=this.getNewOption();if(t){const e=t.index;this.newValues.push(t.value),this.setOptionProp(e,"isCurrentNew",!1),this.setOptionProp(e,"isNew",!0)}else e&&(this.setNewOption(e),this.toggleSelectedProp(this.lastOptionIndex,!0));this.setManagedTimeout(()=>{this.setSearchValue(""),this.focusSearchInput()},0)}afterRenderWrapper(){s.addClass(this.$ele,"vscomp-ele"),this.renderSearch(),this.setEleStyles(),this.setDropboxStyles(),this.setVisibleOptionsCount(),this.setOptionsContainerHeight(),this.addEvents();try{this.setEleProps(),this.keepAlwaysOpen||this.showAsPopup||this.initDropboxPopover(),this.initialSelectedValue?this.setValueMethod(this.initialSelectedValue,this.silentInitialValueSet):this.autoSelectFirstOption&&this.visibleOptions.length&&this.setValueMethod(this.visibleOptions[0].value,this.silentInitialValueSet),this.showOptionsOnlyOnSearch&&this.setSearchValue("",!1,!0),this.initialDisabled&&this.disable(),this.autofocus&&this.focus(),this.isInitialized=!0}catch(e){throw this.destroy(),e}}afterRenderOptions(){const e=this.getVisibleOptions(),t=!this.options.length&&!this.hasServerSearch,i=!t&&!e.length;(!this.allowNewOption||this.hasServerSearch||this.showOptionsOnlyOnSearch)&&(s.toggleClass(this.$allWrappers,"has-no-search-results",i),i?(s.setAttr(this.$noSearchResults,"tabindex","0"),s.setAttr(this.$noSearchResults,"aria-hidden","false")):(s.setAttr(this.$noSearchResults,"tabindex","-1"),s.setAttr(this.$noSearchResults,"aria-hidden","true"))),s.toggleClass(this.$allWrappers,"has-no-options",t),t?(s.setAttr(this.$noOptions,"tabindex","0"),s.setAttr(this.$noOptions,"aria-hidden","false")):(s.setAttr(this.$noOptions,"tabindex","-1"),s.setAttr(this.$noOptions,"aria-hidden","true")),this.setOptionAttr(),this.setOptionsPosition(),this.setOptionsTooltip(),document.activeElement!==this.$searchInput&&this.setManagedTimeout(()=>{const e=s.getElementsBySelector(".focused",this.$dropboxContainer)[0];void 0!==e&&e.focus({preventScroll:!0})},20)}afterSetOptionsContainerHeight(e){e&&this.showAsPopup&&this.setVisibleOptions()}afterSetSearchValue(){this.hasServerSearch?(clearTimeout(this.serverSearchTimeout),this.isSilentServerSearch=!1,this.serverSearchTimeout=setTimeout(()=>{this.serverSearch()},this.searchDelay)):this.setVisibleOptionsCount(),this.selectAllOnlyVisible&&this.toggleAllOptionsClass(),this.isClosing||this.focusOption({focusFirst:!0}),this.hasServerSearch||this.announceSearchResults()}afterSetVisibleOptionsCount(){this.scrollToTop(),this.setOptionsHeight(),this.setVisibleOptions(),this.updatePosition()}afterValueSet(){this.scrollToTop(),this.setSearchValue(""),this.renderOptions()}afterSetOptions(e){if(e&&this.setSelectedProp(),this.setOptionsHeight(),this.setVisibleOptions(),this.showOptionsOnlyOnSearch&&this.setSearchValue("",!1,!0),!e){this.isRefreshingOptions=!0;try{this.reset()}finally{this.isRefreshingOptions=!1}}}setProps(e){const s=this.setDefaultProps(e);this.setPropsFromElementAttr(s);const{convertToBoolean:i}=t;this.$ele=s.ele,this.dropboxWrapper=s.dropboxWrapper,this.valueKey=s.valueKey,this.labelKey=s.labelKey,this.descriptionKey=s.descriptionKey,this.aliasKey=s.aliasKey,this.optionHeightText=s.optionHeight,this.optionHeight=parseFloat(this.optionHeightText),this.multiple=i(s.multiple),this.hasSearch=i(s.search),this.searchByStartsWith=i(s.searchByStartsWith),this.searchGroup=i(s.searchGroup),this.hideClearButton=i(s.hideClearButton),this.autoSelectFirstOption=i(s.autoSelectFirstOption),this.hasOptionDescription=i(s.hasOptionDescription),this.silentInitialValueSet=i(s.silentInitialValueSet),this.allowNewOption=i(s.allowNewOption),this.markSearchResults=i(s.markSearchResults),this.showSelectedOptionsFirst=i(s.showSelectedOptionsFirst),this.disableSelectAll=i(s.disableSelectAll),this.keepAlwaysOpen=i(s.keepAlwaysOpen),this.showDropboxAsPopup=i(s.showDropboxAsPopup),this.hideValueTooltipOnSelectAll=i(s.hideValueTooltipOnSelectAll),this.showOptionsOnlyOnSearch=i(s.showOptionsOnlyOnSearch),this.selectAllOnlyVisible=i(s.selectAllOnlyVisible),this.alwaysShowSelectedOptionsCount=i(s.alwaysShowSelectedOptionsCount),this.alwaysShowSelectedOptionsLabel=i(s.alwaysShowSelectedOptionsLabel),this.disableAllOptionsSelectedText=i(s.disableAllOptionsSelectedText),this.showValueAsTags=i(s.showValueAsTags),this.disableOptionGroupCheckbox=i(s.disableOptionGroupCheckbox),this.enableSecureText=i(s.enableSecureText),this.showSecureTextWarning=i(s.showSecureTextWarning,!0),this.setValueAsArray=i(s.setValueAsArray),this.disableValidation=i(s.disableValidation),this.initialDisabled=i(s.disabled),this.required=i(s.required),this.autofocus=i(s.autofocus),this.useGroupValue=i(s.useGroupValue),this.focusSelectedOptionOnOpen=i(s.focusSelectedOptionOnOpen),this.noOptionsText=s.noOptionsText,this.noSearchResultsText=s.noSearchResultsText,this.selectAllText=s.selectAllText,this.searchNormalize=s.searchNormalize,this.searchPlaceholderText=s.searchPlaceholderText,this.searchFormLabel=s.searchFormLabel,this.optionsSelectedText=s.optionsSelectedText,this.optionSelectedText=s.optionSelectedText,this.allOptionsSelectedText=s.allOptionsSelectedText,this.searchResultsText=s.searchResultsText,this.searchResultText=s.searchResultText,this.noOptionsSelectedText=s.noOptionsSelectedText,this.selectedText=s.selectedText,this.loadingText=s.loadingText,this.requiredErrorText=s.requiredErrorText,this.minValuesErrorText=s.minValuesErrorText,this.clearButtonText=s.clearButtonText,this.moreText=s.moreText,this.placeholder=s.placeholder,this.position=s.position,this.textDirection=s.textDirection,this.dropboxWidth=s.dropboxWidth,this.tooltipFontSize=s.tooltipFontSize,this.tooltipAlignment=s.tooltipAlignment,this.tooltipMaxWidth=s.tooltipMaxWidth,this.updatePositionThrottle=s.updatePositionThrottle,this.noOfDisplayValues=parseInt(s.noOfDisplayValues,10),this.zIndex=parseInt(s.zIndex,10),this.maxValues=parseInt(s.maxValues,10),this.minValues=parseInt(s.minValues,10),this.name=s.name,this.additionalClasses=s.additionalClasses,this.additionalDropboxClasses=s.additionalDropboxClasses,this.additionalDropboxContainerClasses=s.additionalDropboxContainerClasses,this.additionalToggleButtonClasses=s.additionalToggleButtonClasses,this.popupDropboxBreakpoint=s.popupDropboxBreakpoint,this.popupPosition=s.popupPosition,this.onServerSearch=s.onServerSearch,this.labelRenderer=s.labelRenderer,this.selectedLabelRenderer=s.selectedLabelRenderer,this.initialSelectedValue=0===s.selectedValue?"0":s.selectedValue,this.emptyValue=s.emptyValue,this.ariaLabelText=s.ariaLabelText,this.ariaLabelledby=s.ariaLabelledby,this.ariaLabelClearButtonText=s.ariaLabelClearButtonText,this.ariaLabelTagClearButtonText=s.ariaLabelTagClearButtonText,this.ariaLabelSearchClearButtonText=s.ariaLabelSearchClearButtonText,this.maxWidth=s.maxWidth,this.searchDelay=s.searchDelay,this.showDuration=parseInt(s.showDuration,10),this.hideDuration=parseInt(s.hideDuration,10),t.prefersReducedMotion()&&(this.showDuration=0,this.hideDuration=0),this.selectedValues=[],this.selectedOptions=[],this.newValues=[],this.events={},this.tooltipEnterDelay=200,this.searchValue="",this.searchValueOriginal="",this.isAllSelected=!1,(void 0===s.search&&this.multiple||this.allowNewOption||this.showOptionsOnlyOnSearch)&&(this.hasSearch=!0),this.hasServerSearch="function"==typeof this.onServerSearch,(this.maxValues||this.hasServerSearch||this.showOptionsOnlyOnSearch)&&(this.disableSelectAll=!0,this.disableOptionGroupCheckbox=!0),this.keepAlwaysOpen&&(this.dropboxWrapper="self"),this.showAsPopup=this.showDropboxAsPopup&&!this.keepAlwaysOpen&&window.innerWidth<=parseFloat(this.popupDropboxBreakpoint),this.hasSearchContainer=this.hasSearch||this.multiple&&!this.disableSelectAll,this.optionsCount=this.getOptionsCount(s.optionsCount),this.halfOptionsCount=Math.ceil(this.optionsCount/2),this.optionsHeight=this.getOptionsHeight(),this.uniqueId=this.getUniqueId(),this.shouldFocusWrapperOnClose=!0,this.isClosing=!1,this.isSilentServerSearch=!1,this.ariaSetSize=0,this.ariaMetadataDirty=!0}setDefaultProps(e){const t=l.globalDefaults,s=s=>void 0!==e[s]?e[s]:t[s],i={dropboxWrapper:"self",valueKey:"value",labelKey:"label",descriptionKey:"description",aliasKey:"alias",ariaLabelText:"Options list",ariaLabelClearButtonText:"Clear button",ariaLabelTagClearButtonText:"Remove option",ariaLabelSearchClearButtonText:"Clear search input",optionsCount:5,noOfDisplayValues:50,optionHeight:"40px",noOptionsText:"No options found",noSearchResultsText:"No results found",selectAllText:"Select All",searchNormalize:!1,searchPlaceholderText:"Search...",searchFormLabel:"Search",clearButtonText:"Clear",moreText:"more...",optionsSelectedText:"options selected",optionSelectedText:"option selected",searchResultsText:"results available",searchResultText:"result available",noOptionsSelectedText:"No options selected",selectedText:"selected",loadingText:"Loading results",requiredErrorText:"This field is required",minValuesErrorText:"Select at least {count} options",allOptionsSelectedText:"All",placeholder:"Select",position:"bottom left",zIndex:s("keepAlwaysOpen")?1:2,tooltipFontSize:"14px",tooltipAlignment:"center",tooltipMaxWidth:"300px",updatePositionThrottle:100,name:"",additionalClasses:"",additionalDropboxClasses:"",additionalDropboxContainerClasses:"",additionalToggleButtonClasses:"",maxValues:0,showDropboxAsPopup:!0,showSecureTextWarning:!0,popupDropboxBreakpoint:"576px",popupPosition:"center",hideValueTooltipOnSelectAll:!0,emptyValue:"",searchDelay:300,focusSelectedOptionOnOpen:!0,showDuration:300,hideDuration:200};s("hasOptionDescription")&&(i.optionsCount=4,i.optionHeight="50px");const o=e=>{const t={};return Object.keys(e||{}).forEach(s=>{void 0!==e[s]&&(t[s]=e[s])}),t};return Object.assign(i,o(t),o(e))}setPropsFromElementAttr(e){const t=e.ele;Object.keys(r).forEach(s=>{let i=t.getAttribute(s);-1===o.indexOf(s)||""!==i&&"true"!==i||(i=!0),i&&(e[r[s]]=i)})}setEleProps(){const{$ele:e}=this;e.virtualSelect=this,e.value=this.multiple?[]:"",e.name=this.name,e.disabled=!1,e.required=this.required,s.toggleAria(this.$allWrappers,"required",this.required),e.autofocus=this.autofocus,e.multiple=this.multiple,e.form=e.closest("form"),e.reset=l.reset,e.setValue=l.setValueMethod,e.setOptions=l.setOptionsMethod,e.setDisabledOptions=l.setDisabledOptionsMethod,e.setEnabledOptions=l.setEnabledOptionsMethod,e.toggleSelectAll=l.toggleSelectAll,e.isAllSelected=l.isAllSelected,e.addOption=l.addOptionMethod,e.getNewValue=l.getNewValueMethod,e.getDisplayValue=l.getDisplayValueMethod,e.getSelectedOptions=l.getSelectedOptionsMethod,e.getDisabledOptions=l.getDisabledOptionsMethod,e.open=l.openMethod,e.close=l.closeMethod,e.focus=l.focusMethod,e.enable=l.enableMethod,e.disable=l.disableMethod,e.destroy=l.destroyMethod,e.validate=l.validateMethod,e.toggleRequired=l.toggleRequiredMethod,this.hasDropboxWrapper&&(this.$dropboxWrapper.virtualSelect=this)}setValueMethod(e,s){const i=Object.create(null),o=Object.create(null);let n=[];const r=this.multiple;let a=t.normalizeValues(e);if(a){if(Array.isArray(a)||(a=[a]),r){const{maxValues:e}=this;e&&a.length>e&&a.splice(e)}else a.length>1&&(a=[a[0]]);this.useGroupValue&&(a=this.setGroupOptionsValue(a)),a.forEach((e,t)=>{i[e]=!0,o[e]=t}),this.allowNewOption&&a&&this.setNewOptionsFromValue(a)}this.options.forEach(e=>{const s=t.normalizeValues(e.value);!0!==i[s]||e.isDisabled||e.isGroupTitle?e.isSelected=!1:(e.isSelected=!0,n.push(e.value))}),r?(this.hasOptionGroup&&this.setGroupsSelectedProp(),n.sort((e,s)=>o[t.normalizeValues(e)]-o[t.normalizeValues(s)])):[n]=n,this.beforeValueSet(),this.setValue(n,{disableEvent:s}),this.afterValueSet()}setGroupOptionsValue(e){const t=[],s={},i=Object.create(null);return e.forEach(e=>{i[e]=!0}),this.options.forEach(e=>{const{value:o}=e,n=!0===i[o];e.isGroupTitle?n&&(s[e.index]=!0):(n||s[e.groupIndex])&&t.push(o)}),t}setGroupsSelectedProp(){const e=this.isAllGroupOptionsSelected.bind(this);this.options.forEach(t=>{t.isGroupTitle&&(t.isSelected=e(t.index))})}setOptionsMethod(e,t){this.setOptions(e),this.afterSetOptions(t)}setDisabledOptionsMethod(e,t=!1){this.setDisabledOptions(e,!0),t||(this.setValueMethod(null),this.toggleAllOptionsClass()),this.setVisibleOptions()}setDisabledOptions(e,t=!1){let s=[];if(e)if(!0===e)t&&this.options.forEach(e=>(e.isDisabled=!0,s.push(e.value),e));else{s=e.map(e=>e.toString());const i=Object.create(null);s.forEach(e=>{i[e]=!0}),t&&this.options.forEach(e=>(e.isDisabled=!0===i[e.value],e))}else t&&this.options.forEach(e=>(e.isDisabled=!1,e));this.disabledOptions=s}setEnabledOptionsMethod(e,t=!1){this.setEnabledOptions(e),t||(this.setValueMethod(null),this.toggleAllOptionsClass()),this.setVisibleOptions()}setEnabledOptions(e){if(void 0===e)return;const t=[];if(!0===e)this.options.forEach(e=>(e.isDisabled=!1,e));else{const s=Object.create(null);e.forEach(e=>{s[e]=!0}),this.options.forEach(e=>{const i=!0!==s[e.value];return e.isDisabled=i,i&&t.push(e.value),e})}this.disabledOptions=t}setOptions(e=[]){const s=[],i=this.disabledOptions.length,{valueKey:o,labelKey:n,descriptionKey:r,aliasKey:a,hasOptionDescription:l}=this,{getString:h,convertToBoolean:p}=t,c=this.secureText.bind(this),u=this.getAlias.bind(this);let d=0,v=!1;const b=Object.create(null);let m=!1;this.disabledOptions.forEach(e=>{b[e]=!0});const g=e=>{"object"!=typeof e&&(e={[o]:e,[n]:e});const f=h(e[o]),x=h(e[n]),S=f,O=c(x),y=e.options,$=!!y,w={index:d,value:S,valueNormalized:S.toLowerCase(),label:O,labelNormalized:this.searchNormalize&&""!==x.trim()?t.normalizeString(x).toLowerCase():x.toLowerCase(),alias:u(e[a]),isVisible:p(e.isVisible,!0),isNew:e.isNew||!1,isGroupTitle:$,classNames:e.classNames};if(m||""!==S||(m=!0),i&&(w.isDisabled=!0===b[S]),e.isGroupOption&&(w.isGroupOption=!0,w.groupIndex=e.groupIndex),l){const s=h(e[r]);w.description=c(s),w.descriptionNormalized=this.searchNormalize&&""!==s.trim()?t.normalizeString(s).toLowerCase():s.toLowerCase()}if(e.customData&&(w.customData=e.customData),s.push(w),d+=1,$){const e=w.index;v=!0,y.forEach(t=>{t.isGroupOption=!0,t.groupIndex=e,g(t)})}};Array.isArray(e)&&e.forEach(g);const f=s.length,{$ele:x}=this;x.options=s,x.length=f,this.options=s,this.visibleOptionsCount=f,this.lastOptionIndex=f-1,this.newValues=[],this.hasOptionGroup=v,this.hasEmptyValueOption=m,this.setSortedOptions()}setServerOptions(e=[]){this.setOptionsMethod(e,!0);const{selectedOptions:t}=this,i=this.options;let o=!1;if(t.length){const e=Object.create(null);o=!0,i.forEach(t=>{e[t.value]=!0}),t.forEach(t=>{!0!==e[t.value]&&(t.isVisible=!1,i.push(t))}),this.setOptionsMethod(i,!0)}this.allowNewOption&&this.searchValue&&(i.some(e=>e.label.toLowerCase()===this.searchValue)||(o=!0,this.setNewOption())),o?(this.setVisibleOptionsCount(),this.multiple&&this.toggleAllOptionsClass(),this.setValueText()):this.updatePosition(),this.setVisibleOptionsCount(),s.removeClass(this.$allWrappers,"server-searching"),this.isInitialized&&!this.isSilentServerSearch&&this.isOpened()&&this.announce(this.getResultsCountMessage())}setSelectedOptions(){this.selectedOptions=this.options.filter(e=>e.isSelected)}setSortedOptions(){this.ariaMetadataDirty=!0;let e=[...this.options];this.showSelectedOptionsFirst&&this.selectedValues.length&&(e=this.hasOptionGroup?this.sortOptionsGroup(e):this.sortOptions(e)),this.sortedOptions=e}setVisibleOptions(){let e=[...this.sortedOptions];const t=2*this.optionsCount,s=this.getVisibleStartIndex(),i=this.getNewOption(),o=s+t-1;let n=0;i&&(i.visibleIndex=n,n+=1),e=e.filter(e=>{let t=!1;return e.isVisible&&!e.isCurrentNew&&(t=n>=s&&n<=o,e.visibleIndex=n,n+=1),t}),i&&(e=[i,...e]),this.visibleOptions=e,this.visibleOptionsCount=e.length,this.renderOptions()}setOptionsPosition(e){const t=parseInt((e||this.getVisibleStartIndex())*this.optionHeight,10);this.$options.style.transform=`translate3d(0, ${t}px, 0)`,s.setData(this.$options,"top",t)}setOptionsTooltip(){const e=this.getVisibleOptions(),{hasOptionDescription:t}=this;e.forEach(e=>{const i=this.$dropboxContainer.querySelector(`.vscomp-option[data-index="${e.index}"]`);s.setData(i.querySelector(".vscomp-option-text"),"tooltip",e.label),t&&s.setData(i.querySelector(".vscomp-option-description"),"tooltip",e.description)})}setValue(e,{disableEvent:i=!1,disableValidation:o=!1}={}){const n=t.normalizeValues(e);this.hasEmptyValueOption&&""===n||n?Array.isArray(n)?this.selectedValues=[...n]:this.selectedValues=[n]:this.selectedValues=[];const r=this.getValue();this.$ele.value=r,this.$hiddenInput.value=this.getInputValue(r),this.isMaxValuesSelected=!!(this.maxValues&&this.maxValues<=this.selectedValues.length),this.toggleAllOptionsClass(),this.setValueText();const a=t.isNotEmpty(this.selectedValues);s.toggleClass(this.$allWrappers,"has-value",a),s.toggleClass(this.$allWrappers,"max-value-selected",this.isMaxValuesSelected),s.setAttr(this.$clearButton,"tabindex",a?"0":"-1"),s.setAria(this.$clearButton,"hidden",!1===a);let l=!0;o||(l=this.validate()),this.isInitialized&&l&&this.announce(this.getSelectionMessage()),i||s.dispatchEvent(this.$ele,"change",!0)}setValueText(){const{multiple:e,selectedValues:i,noOfDisplayValues:o,showValueAsTags:n,$valueText:r,selectedLabelRenderer:a}=this,l=[];let h=[];const p=i.length;let c=0;const u=this.isAllSelected&&!this.hasServerSearch&&!this.disableAllOptionsSelectedText&&!n;if(u&&this.hideValueTooltipOnSelectAll)r.innerHTML=`${this.allOptionsSelectedText} (${p})`;else{this.getSelectedOptions({fullDetails:!0,keepSelectionOrder:!0}).some(e=>{if(e.isCurrentNew)return!1;if(c>=o)return!0;let{label:s}=e;if("function"==typeof a&&(s=a(e)),l.push(s),c+=1,n){const i=this.getTooltipAttrText(s,!0,!0);let o="";this.ariaLabelTagClearButtonText&&(o=`aria-label="${t.getAriaLabelText(s)}, ${t.getAriaLabelText(this.ariaLabelTagClearButtonText)}"`);const n=`\n ${s}\n \n \n \n `;h.push(n)}else h.push(s);return!1});const i=p-o;i>0&&h.push(`+ ${i} ${this.moreText}`);const d=l.join(", ");if(""===d)r.innerHTML=this.placeholder;else if(r.innerHTML=d,e){const{maxValues:e}=this;if(this.alwaysShowSelectedOptionsCount||s.hasEllipsis(r)||e||n){let t=`${p}`;if(e&&(t+=` / ${e}`),u)r.innerHTML=`${this.allOptionsSelectedText} (${p})`;else if(n)r.innerHTML=h.join(""),this.$valueTags=r.querySelectorAll(".vscomp-value-tag"),this.setValueTagAttr();else if(!this.alwaysShowSelectedOptionsLabel){const e=1===p?this.optionSelectedText:this.optionsSelectedText;r.innerHTML=`${t} ${e}`}}else h=[]}}let d="";0===p?d=this.placeholder:n||(d=h.join(", ")),n||s.setData(r,"tooltip",d),e&&(n?this.updatePosition():s.setData(r,"tooltipEllipsisOnly",0===p))}setSearchValue(e,t=!1,i=!1){if(e===this.searchValueOriginal&&!i)return;t||(this.$searchInput.value=e);const o=e.replace(/\\/g,"").toLowerCase().trim();this.searchValue=o,this.searchValueOriginal=e,s.toggleClass(this.$allWrappers,"has-search-value",e),s.setAttr(this.$searchClear,"tabindex",""!==e?"0":"-1"),s.setAria(this.$searchClear,"hidden",""===e),this.afterSetSearchValue()}setVisibleOptionsCount(){let e,s=0,i=!1;const{searchGroup:o,showOptionsOnlyOnSearch:n,searchByStartsWith:r}=this;let{searchValue:a}=this;a=this.searchNormalize&&""!==a.trim()?t.normalizeString(a):a;const l=this.isOptionVisible.bind(this);this.hasOptionGroup&&(e=this.getVisibleOptionGroupsMapping(a)),this.options.forEach(t=>{if(t.isCurrentNew)return;let h;n&&!a?(t.isVisible=!1,h={isVisible:!1,hasExactOption:!1}):h=l({data:t,searchValue:a,hasExactOption:i,visibleOptionGroupsMapping:e,searchGroup:o,searchByStartsWith:r}),h.isVisible&&(s+=1),i||(i=h.hasExactOption)}),this.allowNewOption&&(a&&!i?(this.setNewOption(),s+=1):this.removeNewOption()),this.visibleOptionsCount=s,this.filteredOptionsCount=s,this.ariaMetadataDirty=!0,this.afterSetVisibleOptionsCount()}calculateAriaMetadata(){let e=0,t=0;if((this.sortedOptions&&this.sortedOptions.length?this.sortedOptions:this.options).forEach(s=>{if(s.isCurrentNew)s.filteredIndex=void 0;else if(!0===s.isVisible){const i=s.isGroupTitle&&this.multiple&&!this.disableOptionGroupCheckbox;!s.isGroupTitle||i?(t+=1,e+=1,s.filteredIndex=t):s.filteredIndex=void 0}else s.filteredIndex=void 0}),this.allowNewOption){const s=this.getNewOption();s&&!0===s.isVisible?(t+=1,e+=1,s.filteredIndex=t):s&&(s.filteredIndex=void 0)}this.ariaSetSize=e}setOptionProp(e,t,s){this.options[e]&&(this.options[e][t]=s)}setOptionsHeight(){this.$optionsList.style.height=this.optionHeight*this.visibleOptionsCount+"px"}setOptionsContainerHeight(e){let t;e?this.showAsPopup&&(this.optionsCount=this.getOptionsCount(),this.halfOptionsCount=Math.ceil(this.optionsCount/2),t=this.getOptionsHeight(),this.optionsHeight=t):(t=this.optionsHeight,this.keepAlwaysOpen&&(s.setStyle(this.$noOptions,"height",t),s.setStyle(this.$noSearchResults,"height",t))),s.setStyle(this.$optionsContainer,"max-height",t),this.afterSetOptionsContainerHeight(e)}setNewOption(e){const t=e||this.searchValueOriginal.trim();if(!t)return;this.ariaMetadataDirty=!0;const s=this.getNewOption();if(s){const e=s.index;this.setOptionProp(e,"value",t),this.setOptionProp(e,"label",this.secureText(t))}else{const s={value:t,label:t};e?(s.isNew=!0,this.newValues.push(t)):s.isCurrentNew=!0,this.addOption(s)}}setSelectedProp(){const e=Object.create(null);this.selectedValues.forEach(t=>{e[t]=!0}),this.options.forEach(t=>{!0===e[t.value]&&(t.isSelected=!0)})}setNewOptionsFromValue(e){if(!e)return;const t=this.setNewOption.bind(this),s=Object.create(null);this.options.forEach(e=>{s[e.value]=!0}),e.forEach(e=>{e&&!0!==s[e]&&t(e)})}setDropboxWrapperWidth(){if(this.showAsPopup)return;const e=this.dropboxWidth||`${this.$wrapper.offsetWidth}px`;s.setStyle(this.$dropboxContainer,"max-width",e)}setEleStyles(){const{maxWidth:e}=this,t={};e&&(t["max-width"]=e),s.setStyles(this.$ele,t)}setDropboxStyles(){const{dropboxWidth:e}=this,t={},i={"z-index":this.zIndex};e&&(this.showAsPopup?t["max-width"]=e:i.width=e),s.setStyles(this.$dropboxContainer,i),s.setStyles(this.$dropbox,t)}setOptionAttr(){const{$visibleOptions:e}=this,{options:t}=this,i=`${this.optionHeight}px`,{setStyle:o,getData:n,setData:r}=s;e&&e.length&&e.forEach(e=>{const s=t[n(e,"index")];o(e,"height",i),r(e,"value",s.value)})}setValueTagAttr(){const{$valueTags:e}=this;if(!e||!e.length)return;const{getData:t,setData:i}=s,{options:o}=this;e.forEach(e=>{const s=t(e,"index");if(void 0!==s){const t=o[s];i(e,"value",t.value)}})}setScrollTop(){const{selectedValues:e}=this;if(this.showSelectedOptionsFirst||!this.focusSelectedOptionOnOpen||0===e.length)return;const t=Object.create(null);let s;e.forEach(e=>{t[e]=!0}),this.options.some(e=>!!t[e.value]&&(s=e.visibleIndex,!0)),s&&(this.$optionsContainer.scrollTop=this.optionHeight*s)}getVisibleOptions(){return this.visibleOptions||[]}getValue(){let e;return e=this.multiple?this.useGroupValue?this.getGroupValue():this.selectedValues:this.selectedValues[0]||"",t.normalizeValues(e)}getGroupValue(){const e=[],t={};return this.options.forEach(s=>{if(!s.isSelected)return;const{value:i}=s;s.isGroupTitle?i&&(t[s.index]=!0,e.push(i)):!0!==t[s.groupIndex]&&e.push(i)}),e}getInputValue(e){let t=e;return t&&t.length?this.setValueAsArray&&this.multiple&&(t=JSON.stringify(t)):t=this.emptyValue,t}getFirstVisibleOptionIndex(){return Math.ceil(this.$optionsContainer.scrollTop/this.optionHeight)}getVisibleStartIndex(){let e=this.getFirstVisibleOptionIndex()-this.halfOptionsCount;return e<0&&(e=0),e}getTooltipAttrText(e,t=!1,i=!1){const o={"data-tooltip":e||"","data-tooltip-enter-delay":this.tooltipEnterDelay,"data-tooltip-z-index":this.zIndex,"data-tooltip-font-size":this.tooltipFontSize,"data-tooltip-alignment":this.tooltipAlignment,"data-tooltip-max-width":this.tooltipMaxWidth,"data-tooltip-ellipsis-only":t,"data-tooltip-allow-html":i};return s.getAttributesText(o)}getOptionObj(e){if(!e)return;const{getString:s}=t,i=this.secureText.bind(this),o=s(e.value),n=s(e.label),r=s(e.description);return{index:e.index,value:o,valueNormalized:o.toLowerCase(),label:i(n),labelNormalized:this.searchNormalize&&""!==n.trim()?t.normalizeString(n).toLowerCase():n.toLowerCase(),description:i(r),descriptionNormalized:this.searchNormalize&&""!==r.trim()?t.normalizeString(r).toLowerCase():r.toLowerCase(),alias:this.getAlias(e.alias),isCurrentNew:e.isCurrentNew||!1,isNew:e.isNew||!1,isVisible:!0}}getNewOption(){const e=this.options[this.lastOptionIndex];if(e&&e.isCurrentNew)return e}getOptionIndex(e){let t;return this.options.some(s=>s.value===e&&(t=s.index,!0)),t}getNewValue(){const e=Object.create(null);this.newValues.forEach(t=>{e[t]=!0});const t=this.selectedValues.filter(t=>!0===e[t]);return this.multiple?t:t[0]}getAlias(e){let t=e;return t&&(t=Array.isArray(t)?t.join(","):t.toString().trim(),t=t.toLowerCase()),t||""}getDisplayValue(){const e=[];return this.options.forEach(t=>{t.isSelected&&e.push(t.label)}),this.multiple?e:e[0]||""}getSelectedOptions({fullDetails:e=!1,keepSelectionOrder:t=!1}={}){const{valueKey:s,labelKey:i,selectedValues:o}=this,n=[];if(this.options.forEach(t=>{if(t.isSelected&&!t.isGroupTitle)if(e)n.push(t);else{const e={[s]:t.value,[i]:t.label};t.isNew&&(e.isNew=!0),t.customData&&(e.customData=t.customData),n.push(e)}}),t){const e=Object.create(null);o.forEach((t,s)=>{e[t]=s}),n.sort((t,s)=>e[t.value]-e[s.value])}return this.multiple||e?n:n[0]}getDisabledOptions(){const{valueKey:e,labelKey:t,disabledOptions:s}=this,i=Object.create(null),o=[];return s.forEach(e=>{i[e]=!0}),this.options.forEach(({value:s,label:n})=>{i[s]&&o.push({[e]:s,[t]:n})}),o}getVisibleOptionGroupsMapping(e){let{options:t}=this;const s={},i=this.isOptionVisible.bind(this);return t=this.structureOptionGroup(t),t.forEach(t=>{s[t.index]=t.options.some(t=>i({data:t,searchValue:e}).isVisible)}),s}getOptionsCount(e){let t;if(this.showAsPopup){let e=80*window.innerHeight/100-48;this.hasSearchContainer&&(e-=40),t=Math.floor(e/this.optionHeight)}else t=parseInt(e,10);return t}getOptionsHeight(){return this.optionsCount*this.optionHeight+"px"}isSelectableGroupTitle(e){return e&&s.hasClass(e,"group-title")&&this.multiple&&!this.disableOptionGroupCheckbox}shouldSkipOptionInNavigation(e){return!!e&&(!!s.hasClass(e,"disabled")||s.hasClass(e,"group-title")&&!this.isSelectableGroupTitle(e))}getSibling(e,t){const s="next"===t?"nextElementSibling":"previousElementSibling";let i=e;do{i&&(i=i[s])}while(this.shouldSkipOptionInNavigation(i));return i}getUniqueId(){const e=t.getRandomInt(1e4);return document.querySelector(`#vscomp-ele-wrapper-${e}`)?this.getUniqueId():e}initDropboxPopover(){const e={ele:this.$ele,target:this.$dropboxContainer,position:this.position,zIndex:this.zIndex,margin:4,transitionDistance:30,hideArrowIcon:!0,disableManualAction:!0,disableUpdatePosition:!this.hasDropboxWrapper,updatePositionThrottle:this.updatePositionThrottle,showDuration:this.showDuration,hideDuration:this.hideDuration,afterShow:this.afterShowPopper.bind(this),afterHide:this.afterHidePopper.bind(this)};this.dropboxPopover=new PopoverComponent(e)}openDropbox(e){l.lastInteractedInstance=this;let t="";e||(t=this.$dropboxContainer.style.transition,this.$dropboxContainer.style.transition="none"),this.isSilentOpen=e,l.openInstances.forEach(e=>{if(e!==this){const t=e;t.shouldFocusWrapperOnClose=!1,t.closeDropbox(!0)}}),l.openInstances.add(this),this.isSilentServerSearch=!1,s.setAttr(this.$dropboxWrapper,"tabindex","0"),s.setAria(this.$dropboxWrapper,"hidden",!1),s.setAttr(this.$dropboxContainerTop,"tabindex","0"),s.setAria(this.$dropboxContainerTop,"hidden",!1),s.setAttr(this.$dropboxContainerBottom,"tabindex","0"),s.setAria(this.$dropboxContainerBottom,"hidden",!1),e?s.setStyle(this.$dropboxContainer,"display","inline-flex"):(s.dispatchEvent(this.$ele,"beforeOpen"),s.setAria(this.$wrapper,"expanded",!0)),this.setDropboxWrapperWidth(),s.removeClass(this.$allWrappers,"closed"),s.changeTabIndex(this.$allWrappers,0),e||(this.$dropboxContainer.offsetHeight,this.$dropboxContainer.style.transition=t),this.dropboxPopover&&!e?this.dropboxPopover.show():this.afterShowPopper()}afterShowPopper(){const e=this.isSilentOpen;this.isSilentOpen=!1,e||(this.moveSelectedOptionsFirst(),this.setScrollTop(),s.addClass(this.$allWrappers,"focused"),this.showAsPopup?(s.addClass(this.$body,"vscomp-popup-active"),this.isPopupActive=!0):this.focusElementOnOpen(),s.dispatchEvent(this.$ele,"afterOpen"))}closeDropbox(e){if(this.isSilentClose=e,l.openInstances.delete(this),!1===this.isOpened())return;if(this.keepAlwaysOpen)return void this.removeOptionFocus();const t=document.activeElement,i=t&&this.$wrapper.contains(t)||this.hasDropboxWrapper&&t&&this.$dropboxWrapper.contains(t);this.shouldFocusWrapperOnClose&&l.lastInteractedInstance===this&&!e&&(null===t||t===document.body||i)&&this.$wrapper.focus(),e?s.setStyle(this.$dropboxContainer,"display",""):(s.dispatchEvent(this.$ele,"beforeClose"),s.setAria(this.$wrapper,"expanded",!1),this.removeOptionFocus(),this.setActiveDescendant("")),this.dropboxPopover&&!e?(this.dropboxPopover.hide(),s.setAttr(this.$dropboxWrapper,"tabindex","-1"),s.setAria(this.$dropboxWrapper,"hidden",!0),s.setAttr(this.$dropboxContainerTop,"tabindex","-1"),s.setAria(this.$dropboxContainerTop,"hidden",!0),s.setAttr(this.$dropboxContainerBottom,"tabindex","-1"),s.setAria(this.$dropboxContainerBottom,"hidden",!0)):this.afterHidePopper(),this.isClosing=!0;try{this.setSearchValue("")}finally{this.isClosing=!1}this.hasServerSearch&&(this.isSilentServerSearch=!0)}afterHidePopper(){const e=this.isSilentClose;this.isSilentClose=!1,s.removeClass(this.$allWrappers,"focused"),this.removeOptionFocus(),!e&&this.isPopupActive&&(s.removeClass(this.$body,"vscomp-popup-active"),this.isPopupActive=!1),s.addClass(this.$allWrappers,"closed"),e||s.dispatchEvent(this.$ele,"afterClose"),this.shouldFocusWrapperOnClose=!0,s.setAttr(this.$dropboxWrapper,"tabindex","-1"),s.setAria(this.$dropboxWrapper,"hidden",!0),s.setAttr(this.$dropboxContainerTop,"tabindex","-1"),s.setAria(this.$dropboxContainerTop,"hidden",!0),s.setAttr(this.$dropboxContainerBottom,"tabindex","-1"),s.setAria(this.$dropboxContainerBottom,"hidden",!0)}moveSelectedOptionsFirst(){this.$optionsContainer.scrollTop&&this.selectedValues.length||this.setVisibleOptions(),this.showSelectedOptionsFirst&&(this.setSortedOptions(),this.scrollToTop(),this.setVisibleOptions())}toggleDropbox(){l.lastInteractedInstance=this,this.isOpened()?this.closeDropbox():this.openDropbox()}updatePosition(){this.dropboxPopover&&this.isOpened()&&this.$ele.updatePosition()}isOpened(){return!s.hasClass(this.$wrapper,"closed")}focusSearchInput(){const e=this.$searchInput;e&&e.focus()}focusElementOnOpen(){const e=this.$searchInput,t=!this.options.length&&!this.hasServerSearch;if(e)t&&!this.allowNewOption?(s.setAttr(e,"disabled",""),this.$noOptions.focus()):(e.removeAttribute("disabled"),e.focus());else{const e=this.$dropbox.querySelector('[tabindex="0"]');void 0!==s.getData(e,"index")?this.focusOption({direction:"next"}):e?e.focus():this.focusFirstVisibleOption()}}focusFirstVisibleOption(){let e=this.$optionsContainer.querySelector(`[data-index='${this.getFirstVisibleOptionIndex()}']`);e?(this.shouldSkipOptionInNavigation(e)&&(e=this.getSibling(e,"next")),e&&(s.setAttr(e,"tabindex","0"),this.$optionsContainer.scrollTop=this.optionHeight*this.getFirstVisibleOptionIndex(),this.focusOption({focusFirst:!0}),e.focus())):(e=this.$dropbox.querySelector('[tabindex="0"]'),e&&e.focus())}focusOption({direction:e,$option:t,focusFirst:i}={}){const o=this.$dropboxContainer.querySelector(".vscomp-option.focused");let n;if(t)n=t;else if(!o||i){const e=this.getFirstVisibleOptionIndex();n=this.$dropboxContainer.querySelector(`.vscomp-option[data-visible-index="${e}"]`),this.shouldSkipOptionInNavigation(n)&&(n=this.getSibling(n,"next"))}else n=this.getSibling(o,e);n&&n!==o&&(o&&this.toggleOptionFocusedState(o,!1),this.toggleOptionFocusedState(n,!0),this.toggleFocusedProp(s.getData(n,"index"),!0),this.moveFocusedOptionToView(n))}moveFocusedOptionToView(e){const t=e||this.$dropboxContainer.querySelector(".vscomp-option.focused");if(!t)return;let i;const o=this.$optionsContainer.getBoundingClientRect(),n=t.getBoundingClientRect(),r=o.top,a=o.bottom,l=o.height,h=n.top,p=n.bottom,c=n.height,u=t.offsetTop,d=s.getData(this.$options,"top","number");r>h?i=u+d:a{if(e.isDisabled||e.isGroupTitle||!e.isVisible||e.isSelected)return;const{index:t}=e;if(t>o&&t{e(parseInt(t,10))})}this.setManagedTimeout(()=>{this.renderOptions()},0)}toggleAllOptions(e){if(!this.multiple||this.disableSelectAll)return;const t="boolean"==typeof isSelected?e:!s.hasClass(this.$toggleAllCheckbox,"checked"),i=[],{selectAllOnlyVisible:o}=this;this.options.forEach(e=>{const s=e;if(s.isDisabled||s.isCurrentNew)return;const{isVisible:n,isSelected:r}=s;!t&&(!o||n||!r)||t&&o&&!n&&!r?s.isSelected=!1:(s.isSelected=!0,s.isGroupTitle||i.push(s.value))}),this.toggleAllOptionsClass(t),this.setValue(i),this.renderOptions()}toggleAllOptionsClass(e){if(!this.multiple)return;let t=!1;"boolean"==typeof e||(e=this.isAllOptionsSelected()),!e&&this.selectAllOnlyVisible&&""!==this.searchValue&&(this.visibleOptionsCount>0||""===this.searchValue)&&(t=this.isAllOptionsSelected(!0));const i=e||t;s.toggleClass(this.$toggleAllCheckbox,"checked",i),s.setAria(this.$toggleAllButton,"checked",i),this.isAllSelected=e}isAllOptionsSelected(e){let t=!1;return this.options.length&&this.selectedValues.length&&(t=!this.options.some(t=>!t.isSelected&&!t.isDisabled&&!t.isGroupTitle&&(!e||t.isVisible))),t}isAllGroupOptionsSelected(e){let t=!1;return this.options.length&&(t=!this.options.some(t=>!t.isSelected&&!t.isDisabled&&!t.isGroupTitle&&t.groupIndex===e)),t}toggleGroupOptionsParent(e,t){if(!this.hasOptionGroup||this.disableOptionGroupCheckbox||!e)return;let i=s.getData(e,"groupIndex");void 0!==i&&(i=parseInt(i,10));const o=this.$options.querySelector(`.vscomp-option[data-index="${i}"]`),n="boolean"==typeof t?t:this.isAllGroupOptionsSelected(i);this.toggleGroupTitleCheckbox(o,n),this.toggleGroupTitleProp(i,n)}toggleGroupTitleProp(e,t){const s="boolean"==typeof t?t:this.isAllGroupOptionsSelected(e);this.toggleSelectedProp(e,s)}toggleGroupOptions(e,i){if(!this.hasOptionGroup||this.disableOptionGroupCheckbox||!e)return;const o=s.getData(e,"index","number"),{selectedValues:n,selectAllOnlyVisible:r}=this,a=Object.create(null),{removeItemFromArray:l}=t;n.forEach(e=>{a[e]=!0}),this.options.forEach(e=>{if(e.isDisabled||e.groupIndex!==o)return;const{value:t}=e;!i||r&&!e.isVisible?(e.isSelected=!1,a[t]&&l(n,t)):(e.isSelected=!0,a[t]||n.push(t))}),this.toggleAllOptionsClass(!!i&&null),this.setValue(n),this.setManagedTimeout(()=>{this.renderOptions()},0)}toggleGroupTitleCheckbox(e,t){if(!e)return;const i=s.getData(e,"index","number");this.toggleSelectedProp(i,t),this.toggleOptionSelectedState(e,t)}toggleFocusedProp(e,t=!1){null!==this.focusedOptionIndex&&void 0!==this.focusedOptionIndex&&this.setOptionProp(this.focusedOptionIndex,"isFocused",!1),this.setOptionProp(e,"isFocused",t),this.focusedOptionIndex=e}toggleSelectedProp(e,t=!1){this.setOptionProp(e,"isSelected",t)}scrollToTop(){const{scrollTop:e}=this.$optionsContainer;e>0&&(this.$optionsContainer.scrollTop=0)}reset(e=!1,t=!1){this.options.forEach(e=>{e.isSelected=!1}),this.beforeValueSet(!0),this.setValue(null,{disableEvent:t,disableValidation:e}),this.afterValueSet(),e&&(s.removeClass(this.$allWrappers,"has-error"),s.toggleAria(this.$allWrappers,"invalid",!1),this.setErrorMessage("")),s.dispatchEvent(this.$ele,"reset")}addOption(e,t){if(!e)return;this.lastOptionIndex+=1;const s=this.getOptionObj({...e,index:this.lastOptionIndex});this.options.push(s),this.sortedOptions.push(s),t&&(this.visibleOptionsCount+=1,this.afterSetOptions())}removeOption(e){(e||0===e)&&(this.options.splice(e,1),this.lastOptionIndex-=1)}removeNewOption(){const e=this.getNewOption();e&&(this.ariaMetadataDirty=!0,this.removeOption(e.index))}sortOptions(e){return e.sort((e,t)=>{const s=e.isSelected||e.isAnySelected,i=t.isSelected||t.isAnySelected;return s||i?s&&(!i||e.index{const s=e.options;e.isAnySelected=s.some(e=>e.isSelected),e.isAnySelected&&t(s)}),t(s),this.destructureOptionGroup(s)}isOptionVisible({data:e,searchValue:s,hasExactOption:i,visibleOptionGroupsMapping:o,searchGroup:n,searchByStartsWith:r}){const a=null!=e.valueNormalized?e.valueNormalized:e.value.toLowerCase();let l=e.labelNormalized;if(null==l){const s=(e.label||"").trim();l=this.searchNormalize&&""!==s?t.normalizeString(s).toLowerCase():s.toLowerCase()}const{description:h,alias:p}=e;let{descriptionNormalized:c}=e;if(null==c){const e=h||"";c=this.searchNormalize&&""!==e.trim()?t.normalizeString(e).toLowerCase():e.toLowerCase()}let u=r?l.startsWith(s):l.includes(s);return!e.isGroupTitle||n&&u||(u=o[e.index]),r||!p||u||(u=p.includes(s)),r||!c||u||(u=c.includes(s)),e.isVisible=u,i||(i=l===s||a===s),{isVisible:u,hasExactOption:i}}structureOptionGroup(e){const t=[],s={};return e.forEach(e=>{if(e.isGroupTitle){const i=[];e.options=i,s[e.index]=i,t.push(e)}}),e.forEach(e=>{e.isGroupOption&&s[e.groupIndex].push(e)}),t}destructureOptionGroup(e){let t=[];return e.forEach(e=>{t.push(e),t=t.concat(e.options)}),t}serverSearch(){s.removeClass(this.$allWrappers,"has-no-search-results"),s.addClass(this.$allWrappers,"server-searching"),this.isInitialized&&!this.isSilentServerSearch&&this.isOpened()&&this.announce(this.loadingText),this.setSelectedOptions(),this.onServerSearch(this.searchValue,this)}removeValue(e){const{selectedValues:i}=this,o=s.getData(e,"value");t.removeItemFromArray(i,o),this.setValueMethod(i)}focus(){this.$wrapper.focus()}enable(){this.$ele.disabled=!1,this.$ele.removeAttribute("disabled"),this.$hiddenInput.removeAttribute("disabled"),s.setAria(this.$wrapper,"disabled",!1),s.changeTabIndex(this.$wrapper,0)}disable(){this.$ele.disabled=!0,this.$ele.setAttribute("disabled",""),this.$hiddenInput.setAttribute("disabled",""),s.setAria(this.$wrapper,"disabled",!0),s.changeTabIndex(this.$wrapper,-1),this.$wrapper.blur()}validate(){if(this.disableValidation)return!0;let e=!1,i="";const{selectedValues:o,minValues:n}=this;return this.required&&(t.isEmpty(o)?(e=!0,i=this.requiredErrorText):this.multiple&&n&&o.length{this.managedTimeouts.delete(s),e()},t);return this.managedTimeouts.add(s),s}clearManagedTimeouts(){this.managedTimeouts&&(this.managedTimeouts.forEach(e=>clearTimeout(e)),this.managedTimeouts.clear())}destroy(){if(this.isDestroyed)return;this.isDestroyed=!0;const{$ele:e}=this;e.virtualSelect=void 0,e.value=void 0,e.innerHTML="",l.openInstances.delete(this),this===l.lastInteractedInstance&&(l.lastInteractedInstance=null),this.serverSearchTimeout&&(clearTimeout(this.serverSearchTimeout),this.serverSearchTimeout=null),this.clearManagedTimeouts(),this.scrollAnimationFrame&&(cancelAnimationFrame(this.scrollAnimationFrame),this.scrollAnimationFrame=null),this.removeEvents(),this.hasDropboxWrapper&&(this.$dropboxWrapper.virtualSelect=void 0,this.$dropboxWrapper.remove()),this.dropboxPopover&&this.dropboxPopover.destroy(),s.removeClass(e,"vscomp-ele"),this.events={},l.unregisterInstance(this)}createSecureTextElements(){this.$secureDiv=document.createElement("div"),this.$secureText=document.createTextNode(""),this.$secureDiv.appendChild(this.$secureText)}secureText(e){return e&&this.enableSecureText?(this.$secureText.nodeValue=e,this.$secureDiv.innerHTML):e}warnIfSecureTextDisabled(){l.secureTextWarningShown||this.enableSecureText||!this.showSecureTextWarning||(l.secureTextWarningShown=!0,console.warn("[virtual-select] Option text (label, value, description) and any `customData` used in markup are rendered as HTML and are NOT escaped because `enableSecureText` is disabled (the default, kept off for performance on large datasets). If any option text can come from untrusted input, set `enableSecureText: true` to prevent XSS. Docs: https://sa-si-dev.github.io/virtual-select/#/properties"))}announce(e){if(!this.$liveRegion)return;const s=t.getPlainText(e||"");this.$liveRegion.textContent!==s&&(this.$liveRegion.textContent=s)}getResultsCountMessage(){const e=this.filteredOptionsCount||0;return 0===e?this.noSearchResultsText:`${e} ${1===e?this.searchResultText:this.searchResultsText}`}getSelectionMessage(){const e=this.selectedValues.length;return 0===e?this.noOptionsSelectedText:this.multiple?`${e} ${1===e?this.optionSelectedText:this.optionsSelectedText}`:`${this.getDisplayValue()||this.selectedValues[0]} ${this.selectedText}`}announceSearchResults(){this.isInitialized&&this.isOpened()&&document.activeElement===this.$searchInput&&this.announce(this.getResultsCountMessage())}toggleRequired(e){this.required=t.convertToBoolean(e),this.$ele.required=this.required,s.toggleAria(this.$allWrappers,"required",this.required),this.required||(s.toggleClass(this.$allWrappers,"has-error",!1),s.toggleAria(this.$allWrappers,"invalid",!1),this.setErrorMessage(""))}toggleOptionSelectedState(e,t){let i=t;void 0===i&&(i=!s.hasClass(e,"selected")),s.toggleClass(e,"selected",i),s.setAria(e,"selected",i)}toggleOptionFocusedState(e,t){e&&(s.toggleClass(e,"focused",t),s.setAttr(e,"tabindex",t?"0":"-1"),t&&document.activeElement!==this.$searchInput&&e.focus(),this.setActiveDescendant(t?e.id:""))}setActiveDescendant(e){s.toggleAria(this.$wrapper,"activedescendant",!!e,e),s.toggleAria(this.$searchInput,"activedescendant",!!e,e)}static setGlobalDefaults(e){if(!e||"object"!=typeof e)return;const t={...e};delete t.ele,delete t.options,l.globalDefaults={...l.globalDefaults,...t}}static resetGlobalDefaults(){l.globalDefaults={}}static getGlobalDefaults(){return{...l.globalDefaults}}static init(e){let t=e.ele;if(!t)return;let s=!1;if("string"==typeof t){t=document.querySelectorAll(t);const e=t.length;if(0===e)return;1===e&&(s=!0)}void 0!==t.length&&void 0!==t.forEach||(t=[t],s=!0);const i=[];return t.forEach(t=>{t.virtualSelect?i.push(t.virtualSelect):(e.ele=t,"SELECT"===t.tagName&&l.setPropsFromSelect(e),i.push(new l(e)))}),s?i[0]:i}static getAttrProps(){const{convertPropToDataAttr:e}=s,t={};return n.forEach(e=>{t[e]=e}),a.forEach(s=>{t[e(s)]=s}),t}static setPropsFromSelect(e){const t=e.ele,i=[],n=[],a=e=>{const t=[];return Array.from(e.children).forEach(e=>{const{value:s}=e,o={value:s};"OPTGROUP"===e.tagName?(o.label=e.getAttribute("label"),o.options=a(e)):o.label=e.innerHTML,t.push(o),e.disabled&&i.push(s),e.selected&&n.push(s)}),t},l=a(t),h=document.createElement("div");s.setAttrFromEle(t,h,Object.keys(r),o),t.parentNode.insertBefore(h,t),t.remove(),e.ele=h,e.options=l,e.disabledOptions=i,e.selectedValue=n}static onFormReset(e){const t=e.target.closest("form");t&&t.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{e.parentElement.virtualSelect.reset(!0)})}static onFormSubmit(e){l.validate(e.target.closest("form"))||e.preventDefault()}static validate(e){if(!e)return!0;let t=!1;return e.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{const s=e.parentElement.virtualSelect.validate();t||s||(t=!0)}),!t}static reset(e=!1,t=!1){this.virtualSelect.reset(e,t)}static setValueMethod(...e){this.virtualSelect.setValueMethod(...e)}static setOptionsMethod(...e){this.virtualSelect.setOptionsMethod(...e)}static setDisabledOptionsMethod(...e){this.virtualSelect.setDisabledOptionsMethod(...e)}static setEnabledOptionsMethod(...e){this.virtualSelect.setEnabledOptionsMethod(...e)}static toggleSelectAll(e){this.virtualSelect.toggleAllOptions(e)}static isAllSelected(){return this.virtualSelect.isAllSelected}static addOptionMethod(e){this.virtualSelect.addOption(e,!0)}static getNewValueMethod(){return this.virtualSelect.getNewValue()}static getDisplayValueMethod(){return this.virtualSelect.getDisplayValue()}static getSelectedOptionsMethod(e){return this.virtualSelect.getSelectedOptions(e)}static getDisabledOptionsMethod(){return this.virtualSelect.getDisabledOptions()}static openMethod(){return this.virtualSelect.openDropbox()}static closeMethod(){return this.virtualSelect.closeDropbox()}static focusMethod(){return this.virtualSelect.focus()}static enableMethod(){return this.virtualSelect.enable()}static disableMethod(){return this.virtualSelect.disable()}static destroyMethod(){return this.virtualSelect.destroy()}static validateMethod(){return this.virtualSelect.validate()}static toggleRequiredMethod(e){return this.virtualSelect.toggleRequired(e)}static onResizeMethod(){document.querySelectorAll(".vscomp-ele-wrapper").forEach(e=>{const t=e.parentElement&&e.parentElement.virtualSelect;t&&t.onResize()})}}l.onResizeThrottled=t.throttle(l.onResizeMethod,100),r=l.getAttrProps(),window.VirtualSelect=l,l.openInstances=new Set,l.domObserver=null,l.activeInstances=new Set,l.hasGlobalListeners=!1,l.lastInteractedInstance=null,l.secureTextWarningShown=!1,l.globalDefaults={},"undefined"!=typeof NodeList&&NodeList.prototype&&!NodeList.prototype.forEach&&(NodeList.prototype.forEach=Array.prototype.forEach)}(),function(){"use strict";function e(e){return function(e){if(Array.isArray(e))return t(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,s){if(e){if("string"==typeof e)return t(e,s);var i=Object.prototype.toString.call(e).slice(8,-1);return"Object"===i&&e.constructor&&(i=e.constructor.name),"Map"===i||"Set"===i?Array.from(e):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?t(e,s):void 0}}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function t(e,t){(null==t||t>e.length)&&(t=e.length);for(var s=0,i=new Array(t);ss-o-t.width?"left":"right",vertical:n>i-n-t.height?"top":"bottom"}}},{key:"getAbsoluteCoords",value:function(e){if(e){var t=e.getBoundingClientRect(),s=window.pageXOffset,i=window.pageYOffset;return{width:t.width,height:t.height,top:t.top+i,right:t.right+s,bottom:t.bottom+i,left:t.left+s}}}},{key:"getCoords",value:function(e){return e?e.getBoundingClientRect():{}}},{key:"getData",value:function(e,t,s){if(e){var i=e?e.dataset[t]:"";return"number"===s?i=parseFloat(i)||0:"true"===i?i=!0:"false"===i&&(i=!1),i}}},{key:"setData",value:function(e,t,s){e&&(e.dataset[t]=s)}},{key:"setStyle",value:function(e,t,s){e&&(e.style[t]=s)}},{key:"show",value:function(e){var s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"block";t.setStyle(e,"display",s)}},{key:"hide",value:function(e){t.setStyle(e,"display","none")}},{key:"getHideableParent",value:function(e){for(var t,s=e.parentElement;s;){var i=getComputedStyle(s).overflow;if(-1!==i.indexOf("scroll")||-1!==i.indexOf("auto")){t=s;break}s=s.parentElement}return t}}],s&&function(e,t){for(var s=0;sx?x-b:M:w+p>L&&("right"===T?n="left":w=L+bS?S-u:P:C+c>I&&("bottom"===T?n="top":C=I+up-j&&(G=p-j):"left"!==T&&"right"!==T||((R=g/2+f-H)c-j&&(R=c-j)),s.setStyle(this.$arrowEle,"transform","translate3d(".concat(parseInt(G),"px, ").concat(parseInt(R),"px, 0) ").concat(K))}s.hide(this.$popperEle)}},{key:"resetPosition",value:function(){s.setStyle(this.$popperEle,"transform","none"),this.setPosition()}},{key:"show",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},i=t.resetPosition,o=t.data;clearTimeout(this.exitDelayTimeout),clearTimeout(this.hideDurationTimeout),i&&this.resetPosition(),this.enterDelayTimeout=setTimeout(function(){var t=s.getData(e.$popperEle,"left"),i=s.getData(e.$popperEle,"top"),n="translate3d(".concat(parseInt(t),"px, ").concat(parseInt(i),"px, 0)"),r=e.showDuration;s.show(e.$popperEle,"inline-flex"),s.getCoords(e.$popperEle),s.setStyle(e.$popperEle,"transitionDuration",r+"ms"),s.setStyle(e.$popperEle,"transform",n),s.setStyle(e.$popperEle,"opacity",1),e.showDurationTimeout=setTimeout(function(){"function"==typeof e.afterShowCallback&&e.afterShowCallback(o)},r)},this.enterDelay)}},{key:"hide",value:function(){var e=this,t=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).data;clearTimeout(this.enterDelayTimeout),clearTimeout(this.showDurationTimeout),this.exitDelayTimeout=setTimeout(function(){if(e.$popperEle){var i=parseInt(s.getData(e.$popperEle,"fromLeft")),o=parseInt(s.getData(e.$popperEle,"fromTop")),n="translate3d(".concat(i,"px, ").concat(o,"px, 0)"),r=e.hideDuration;s.setStyle(e.$popperEle,"transitionDuration",r+"ms"),s.setStyle(e.$popperEle,"transform",n),s.setStyle(e.$popperEle,"opacity",0),e.hideDurationTimeout=setTimeout(function(){s.hide(e.$popperEle),"function"==typeof e.afterHideCallback&&e.afterHideCallback(t)},r)}},this.exitDelay)}},{key:"updatePosition",value:function(){s.setStyle(this.$popperEle,"transitionDuration","0ms"),this.resetPosition();var e=parseInt(s.getData(this.$popperEle,"left")),t=parseInt(s.getData(this.$popperEle,"top"));s.show(this.$popperEle,"inline-flex"),s.setStyle(this.$popperEle,"transform","translate3d(".concat(e,"px, ").concat(t,"px, 0)"))}}],t&&function(e,t){for(var s=0;s1&&void 0!==arguments[1]&&arguments[1]}},{key:"removeArrayEmpty",value:function(e){return Array.isArray(e)&&e.length?e.filter(function(e){return!!e}):[]}},{key:"throttle",value:function(e,t){var s,i=0;return function(){for(var o=arguments.length,n=new Array(o),r=0;re.length)&&(t=e.length);for(var s=0,i=new Array(t);s'),e=this.$popover.querySelector(".pop-comp-arrow")),this.$arrowEle=e}}},{key:"destroy",value:function(){this.removeEvents()}}])&&c(t.prototype,s),o&&c(t,o),Object.defineProperty(t,"prototype",{writable:!1}),t;var t,s,o}();d=m.getAttrProps(),window.PopoverComponent=m}(); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 376c828..ba50b63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "virtual-select-plugin", - "version": "1.3.0", + "version": "1.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "virtual-select-plugin", - "version": "1.3.0", + "version": "1.4.0", "license": "ISC", "dependencies": { "tooltip-plugin": "^1.0.16" @@ -4014,9 +4014,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.11.11", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.11.tgz", - "integrity": "sha512-/yImnXwyTvgMkhgekLHok/Rx5vO6E0BmStWlSqKWMVm2a2ITuZ1Tn+9bgLS+gZRdZmWtd8nxuhHpdmCUOWsTQQ==", + "version": "2.11.13", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.13.tgz", + "integrity": "sha512-k9HNuUVMlqVjQ9UHzfPjIqiDbWw7WqT1AoT7GL8VwvF3r0ZfArtgiSPAlmupyNquNgOJHTuH4CKYf8ttMTWBTQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4285,9 +4285,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001806", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", - "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "version": "1.0.30001809", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz", + "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index 19a6ceb..87d66df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "virtual-select-plugin", - "version": "1.3.0", + "version": "1.4.0", "description": "A javascript plugin for dropdown with virtual scroll", "scripts": { "start": "webpack --mode development --watch", From d49f1d08a31cf996f9762253fdf01e2b15517f78 Mon Sep 17 00:00:00 2001 From: gnbm Date: Mon, 10 Aug 2026 13:32:18 +0100 Subject: [PATCH 2/2] perf(test): disable Cypress video recording Failure screenshots already cover debugging, so encoding video for every spec run was pure overhead with no one consuming it. --- cypress.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/cypress.config.ts b/cypress.config.ts index 3f6255e..f142707 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -5,5 +5,6 @@ export default defineConfig({ testIsolation: false, baseUrl: 'http://localhost:3001/#/', screenshotOnRunFailure: true, + video: false, }, });