thekselect 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +338 -0
- package/dist/core/config-utils.d.ts +5 -0
- package/dist/core/dom-renderer.d.ts +38 -0
- package/dist/core/event-emitter.d.ts +7 -0
- package/dist/core/options-logic.d.ts +4 -0
- package/dist/core/selection-logic.d.ts +20 -0
- package/dist/core/state.d.ts +10 -0
- package/dist/core/thekselect.d.ts +42 -0
- package/dist/core/types.d.ts +40 -0
- package/dist/css/base.css +37 -0
- package/dist/css/blue.css +14 -0
- package/dist/css/bootstrap.css +15 -0
- package/dist/css/dark.css +14 -0
- package/dist/css/forest.css +14 -0
- package/dist/css/gray.css +14 -0
- package/dist/css/material.css +15 -0
- package/dist/css/red.css +14 -0
- package/dist/css/tailwind.css +15 -0
- package/dist/index.d.ts +2 -0
- package/dist/thekselect.js +1169 -0
- package/dist/thekselect.min.js +1 -0
- package/dist/thekselect.umd.cjs +1171 -0
- package/dist/thekselect.umd.min.cjs +1 -0
- package/dist/utils/debounce.d.ts +4 -0
- package/dist/utils/dom.d.ts +2 -0
- package/dist/utils/event-manager.d.ts +15 -0
- package/dist/utils/styles.d.ts +2 -0
- package/package.json +74 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=class{state;listeners=/* @__PURE__ */new Set;constructor(e){this.state={...e}}getState(){return{...this.state}}setState(e){const t=this.state;this.state={...this.state,...e},Object.keys(e).some(n=>{const s=e[n],i=t[n];return Array.isArray(s)&&Array.isArray(i)?s.length!==i.length||s.some((e,t)=>e!==i[t]):s!==i})&&this.notify()}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}notify(){const e=this.getState();this.listeners.forEach(t=>t(e))}},t=!1,n=class{wrapper;control;selectionContainer;indicatorsContainer;placeholderElement;input;dropdown;optionsList;lastState=null;lastFilteredOptions=[];constructor(e,t,n){this.config=e,this.id=t,this.callbacks=n}normalizeHeight(e){if("number"==typeof e)return`${e}px`;const t=e.trim();return/^\d+(\.\d+)?$/.test(t)?`${t}px`:t}applyHeight(e){const t=this.normalizeHeight(e);this.wrapper.style.setProperty("--thek-input-height",t),this.dropdown.style.setProperty("--thek-input-height",t)}createDom(){if(this.wrapper=document.createElement("div"),this.wrapper.className="thek-select",this.config.disabled&&this.wrapper.classList.add("thek-disabled"),this.config.multiple&&this.wrapper.classList.add("thek-multiple"),this.control=document.createElement("div"),this.control.className="thek-control",this.control.setAttribute("role","combobox"),this.control.setAttribute("aria-expanded","false"),this.control.setAttribute("aria-haspopup","listbox"),this.control.setAttribute("aria-controls",`${this.id}-list`),this.selectionContainer=document.createElement("div"),this.selectionContainer.className="thek-selection",this.placeholderElement=document.createElement("span"),this.placeholderElement.className="thek-placeholder",this.placeholderElement.textContent=this.config.placeholder,this.indicatorsContainer=document.createElement("div"),this.indicatorsContainer.className="thek-indicators",this.indicatorsContainer.innerHTML='<i class="fa-solid fa-chevron-down thek-arrow"></i>',this.control.appendChild(this.selectionContainer),this.control.appendChild(this.placeholderElement),this.control.appendChild(this.indicatorsContainer),this.dropdown=document.createElement("div"),this.dropdown.className="thek-dropdown",this.dropdown.hidden=!0,this.config.searchable){const e=document.createElement("div");e.className="thek-search-wrapper",e.innerHTML='<i class="fa-solid fa-magnifying-glass thek-search-icon"></i>',this.input=document.createElement("input"),this.input.className="thek-input",this.input.type="text",this.input.autocomplete="off",this.input.placeholder="Search...",this.input.setAttribute("aria-autocomplete","list"),e.appendChild(this.input),this.dropdown.appendChild(e)}else this.input=document.createElement("input"),this.input.type="hidden";this.optionsList=document.createElement("ul"),this.optionsList.className="thek-options",this.optionsList.id=`${this.id}-list`,this.optionsList.setAttribute("role","listbox"),this.optionsList.addEventListener("scroll",()=>this.handleOptionsScroll()),this.optionsList.addEventListener("wheel",e=>this.handleOptionsWheel(e),{passive:!1}),this.dropdown.appendChild(this.optionsList),this.wrapper.appendChild(this.control),document.body.appendChild(this.dropdown),this.applyHeight(this.config.height)}render(e,t){this.lastState=e,this.lastFilteredOptions=t,this.control.setAttribute("aria-expanded",e.isOpen.toString()),this.dropdown.hidden=!e.isOpen,this.wrapper.classList.toggle("thek-open",e.isOpen),e.isLoading?this.indicatorsContainer.innerHTML='<i class="fa-solid fa-circle-notch fa-spin text-muted"></i>':this.indicatorsContainer.innerHTML='<i class="fa-solid fa-chevron-down thek-arrow"></i>',this.renderSelectionContent(e),this.renderOptionsContent(e,t),e.isOpen&&this.positionDropdown()}renderSelectionContent(e){this.selectionContainer.innerHTML="";const t=e.selectedValues.length>0;if(this.placeholderElement.style.display=t?"none":"block",this.selectionContainer.style.display=t?"flex":"none",t){const t=this.config.valueField,n=this.config.displayField;if(this.config.multiple)if(e.selectedValues.length>this.config.maxSelectedLabels){const t=document.createElement("span");t.className="thek-summary-text",t.textContent=`${e.selectedValues.length} items selected`,this.selectionContainer.appendChild(t)}else e.selectedValues.forEach((s,i)=>{const o=e.options.find(e=>e[t]===s)||e.selectedOptionsByValue[s]||{[t]:s,[n]:s},a=document.createElement("span");a.className="thek-tag",a.draggable=!0,a.dataset.index=i.toString(),a.dataset.value=s;const r=document.createElement("span");r.className="thek-tag-label";const l=this.config.renderSelection(o);l instanceof HTMLElement?r.appendChild(l):r.textContent=l,a.appendChild(r);const d=document.createElement("span");d.className="thek-tag-remove",d.innerHTML="×",d.addEventListener("click",e=>{e.stopPropagation(),this.callbacks.onSelect(o)}),a.appendChild(d),this.setupTagDnd(a),this.selectionContainer.appendChild(a)});else{const n=e.selectedValues[0],s=e.options.find(e=>e[t]===n)||e.selectedOptionsByValue[n];if(s){const e=this.config.renderSelection(s);e instanceof HTMLElement?this.selectionContainer.appendChild(e):this.selectionContainer.textContent=e}}}}renderOptionsContent(e,t,n=!0,s){this.optionsList.innerHTML="";const i=this.config.valueField,o=this.config.displayField;if(e.isLoading&&0===t.length){const e=document.createElement("li");return e.className="thek-option thek-loading",e.textContent="Loading...",void this.optionsList.appendChild(e)}const a=this.config.canCreate&&e.inputValue&&!t.some(t=>t[o]&&t[o].toString().toLowerCase()===e.inputValue.toLowerCase()),r=this.config.virtualize&&t.length>=this.config.virtualThreshold&&!a,l=Math.max(20,this.config.virtualItemHeight),d=Math.max(0,this.config.virtualOverscan);if(r){const o=this.optionsList.clientHeight||240;if(n&&e.focusedIndex>=0&&e.focusedIndex<t.length){const t=e.focusedIndex*l,n=t+l,s=this.optionsList.scrollTop,i=s+o;t<s?this.optionsList.scrollTop=t:n>i&&(this.optionsList.scrollTop=n-o)}const a=s??this.optionsList.scrollTop,r=Math.max(0,Math.floor(a/l)-d),h=Math.min(t.length,Math.ceil((a+o)/l)+d);r>0&&this.optionsList.appendChild(this.createSpacer(r*l));for(let n=r;n<h;n++)this.optionsList.appendChild(this.createOptionItem(t[n],n,e,i));h<t.length&&this.optionsList.appendChild(this.createSpacer((t.length-h)*l)),"number"==typeof s&&(this.optionsList.scrollTop=s)}else t.forEach((t,n)=>{this.optionsList.appendChild(this.createOptionItem(t,n,e,i))});const h=t.some(t=>t[o]&&t[o].toString().toLowerCase()===e.inputValue.toLowerCase());if(this.config.canCreate&&e.inputValue&&!h){const n=document.createElement("li");n.className="thek-option thek-create",n.textContent=this.config.createText.replace("{%t}",e.inputValue),e.focusedIndex===t.length&&n.classList.add("thek-focused"),n.addEventListener("click",t=>{t.stopPropagation(),this.callbacks.onCreate(e.inputValue)}),this.optionsList.appendChild(n)}if(!(0!==t.length||this.config.canCreate&&e.inputValue)){const e=document.createElement("li");e.className="thek-option thek-no-results",e.textContent="No results found",this.optionsList.appendChild(e)}const c=e.focusedIndex>=0&&e.focusedIndex<t.length&&document.getElementById(`${this.id}-opt-${e.focusedIndex}`)?`${this.id}-opt-${e.focusedIndex}`:null;this.config.searchable&&(c?this.input.setAttribute("aria-activedescendant",c):this.input.removeAttribute("aria-activedescendant"))}createSpacer(e){const t=document.createElement("li");return t.style.height=`${e}px`,t.style.padding="0",t.style.margin="0",t.style.listStyle="none",t.setAttribute("aria-hidden","true"),t}createOptionItem(e,t,n,s){const i=document.createElement("li");i.className="thek-option",i.id=`${this.id}-opt-${t}`;const o=n.selectedValues.includes(e[s]);if(e.disabled&&i.classList.add("thek-disabled"),o&&i.classList.add("thek-selected"),n.focusedIndex===t&&i.classList.add("thek-focused"),i.setAttribute("role","option"),i.setAttribute("aria-selected",o.toString()),this.config.multiple){const e=document.createElement("div");e.className="thek-checkbox",o&&(e.innerHTML='<i class="fa-solid fa-check"></i>'),i.appendChild(e)}const a=document.createElement("span");a.className="thek-option-label";const r=this.config.renderOption(e);return r instanceof HTMLElement?a.appendChild(r):a.textContent=r,i.appendChild(a),i.addEventListener("click",t=>{t.stopPropagation(),this.callbacks.onSelect(e)}),i}handleOptionsScroll(){if(!this.config.virtualize||!this.lastState)return;const e=this.optionsList.scrollTop;this.renderOptionsContent(this.lastState,this.lastFilteredOptions,!1,e)}handleOptionsWheel(e){if(!this.config.virtualize)return;const t=this.optionsList,n=t.scrollTop<=0,s=t.scrollTop+t.clientHeight>=t.scrollHeight-1,i=e.deltaY<0,o=e.deltaY>0;(i&&!n||o&&!s)&&(e.preventDefault(),t.scrollTop+=e.deltaY)}positionDropdown(){const e=this.control.getBoundingClientRect(),t=document.documentElement.clientWidth,n=window.scrollX,s=window.scrollY;this.dropdown.style.position="absolute",this.dropdown.style.zIndex="9999";let i=e.width;i>t-20&&(i=t-20),this.dropdown.style.width=`${i}px`;let o=e.left+n;e.left+i>t&&(o=t-i-10+n),o<n+10&&(o=n+10),this.dropdown.style.left=`${o}px`,this.dropdown.style.top=`${e.bottom+s}px`}setupTagDnd(e){e.addEventListener("dragstart",t=>{t.dataTransfer?.setData("text/plain",e.dataset.index),e.classList.add("thek-dragging")}),e.addEventListener("dragend",()=>{e.classList.remove("thek-dragging")}),e.addEventListener("dragover",t=>{t.preventDefault(),e.classList.add("thek-drag-over")}),e.addEventListener("dragleave",()=>{e.classList.remove("thek-drag-over")}),e.addEventListener("drop",t=>{t.preventDefault(),e.classList.remove("thek-drag-over");const n=parseInt(t.dataTransfer?.getData("text/plain")||"-1"),s=parseInt(e.dataset.index);-1!==n&&n!==s&&this.callbacks.onReorder(n,s)})}setHeight(e){this.config.height=e,this.applyHeight(e)}updateConfig(e){this.config={...this.config,...e}}destroy(){this.wrapper.parentNode&&this.wrapper.parentNode.removeChild(this.wrapper),this.dropdown.parentNode&&this.dropdown.parentNode.removeChild(this.dropdown)}},s=async e=>[];function i(e){return e.loadOptions!==s}function o(e,t){if(i(e)&&t.inputValue)return t.options;const n=t.inputValue.toLowerCase(),s=e.displayField,o=t.options.filter(e=>{const t=e[s];return null!=t&&t.toString().toLowerCase().includes(n)});if(null!=e.maxOptions){const t=Math.max(0,e.maxOptions);return o.slice(0,t)}return o}function a(e,t,n,s){const i={};s.forEach(t=>{const n=t[e];"string"==typeof n&&(i[n]=t)});const o={};return t.forEach(e=>{const t=i[e]||n[e];t&&(o[e]=t)}),o}var r=class{listeners=/* @__PURE__ */new Map;on(e,t){return this.listeners.has(e)||this.listeners.set(e,/* @__PURE__ */new Set),this.listeners.get(e).add(t),()=>this.off(e,t)}off(e,t){const n=this.listeners.get(e);n&&(n.delete(t),0===n.size&&this.listeners.delete(e))}emit(e,t){this.listeners.has(e)&&this.listeners.get(e).forEach(e=>e(t))}},l=class e{static instance;resizeListeners=/* @__PURE__ */new Set;scrollListeners=/* @__PURE__ */new Set;clickListeners=/* @__PURE__ */new Set;constructor(){"undefined"!=typeof window&&(window.addEventListener("resize",e=>this.notify(this.resizeListeners,e)),window.addEventListener("scroll",e=>this.notify(this.scrollListeners,e),!0),document.addEventListener("click",e=>this.notify(this.clickListeners,e)))}static getInstance(){return e.instance||(e.instance=new e),e.instance}notify(e,t){e.forEach(e=>e(t))}onResize(e){return this.resizeListeners.add(e),()=>this.resizeListeners.delete(e)}onScroll(e){return this.scrollListeners.add(e),()=>this.scrollListeners.delete(e)}onClick(e){return this.clickListeners.add(e),()=>this.clickListeners.delete(e)}}.getInstance(),d=class d{static globalDefaults={};config;stateManager;renderer;id;events=new r;originalElement;unsubscribeEvents=[];unsubscribeState;remoteRequestId=0;isDestroyed=!1;focusTimeoutId=null;constructor(i,o={}){!function(){if(t||"undefined"==typeof document)return;const e=document.createElement("style");e.id="thekselect-base-styles",e.textContent=":root {\n --thek-primary: #0f172a;\n --thek-primary-light: #f1f5f9;\n --thek-bg-surface: #ffffff;\n --thek-bg-panel: #f8fafc;\n --thek-bg-subtle: #f1f5f9;\n --thek-border: #e2e8f0;\n --thek-border-strong: #cbd5e1;\n --thek-text-main: #0f172a;\n --thek-text-muted: #64748b;\n --thek-text-inverse: #ffffff;\n --thek-danger: #ef4444;\n --thek-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);\n --thek-input-height: 40px;\n --thek-height-sm: 32px;\n --thek-height-md: 40px;\n --thek-height-lg: 48px;\n --thek-item-padding: 8px 10px;\n --thek-font-family: inherit;\n --thek-border-radius: 8px;\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --thek-primary: #38bdf8;\n --thek-primary-light: rgba(56, 189, 248, 0.15);\n --thek-bg-surface: #0f172a;\n --thek-bg-panel: #334155;\n --thek-bg-subtle: #475569;\n --thek-border: #334155;\n --thek-border-strong: #475569;\n --thek-text-main: #f8fafc;\n --thek-text-muted: #94a3b8;\n --thek-text-inverse: #0f172a;\n --thek-danger: #f43f5e;\n --thek-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -4px rgba(0, 0, 0, 0.4);\n }\n}\n\n[data-theme='dark'] {\n --thek-primary: #38bdf8;\n --thek-primary-light: rgba(56, 189, 248, 0.15);\n --thek-bg-surface: #0f172a;\n --thek-bg-panel: #334155;\n --thek-bg-subtle: #475569;\n --thek-border: #334155;\n --thek-border-strong: #475569;\n --thek-text-main: #f8fafc;\n --thek-text-muted: #94a3b8;\n --thek-text-inverse: #0f172a;\n --thek-danger: #f43f5e;\n --thek-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -4px rgba(0, 0, 0, 0.4);\n}\n\n.thek-select {\n position: relative;\n width: 100%;\n font-family: var(--thek-font-family);\n box-sizing: border-box;\n}\n\n.thek-select *, .thek-dropdown * {\n box-sizing: border-box;\n}\n\n.thek-control {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 12px;\n cursor: pointer;\n min-height: var(--thek-input-height);\n background-color: var(--thek-bg-surface);\n color: var(--thek-text-main);\n border: 1px solid var(--thek-border);\n border-radius: var(--thek-border-radius);\n transition: all 0.2s ease;\n}\n\n.thek-control:hover {\n border-color: var(--thek-border-strong);\n}\n\n.thek-select.thek-open .thek-control {\n border-color: var(--thek-primary);\n box-shadow: 0 0 0 2px var(--thek-primary-light);\n}\n\n.thek-placeholder {\n color: var(--thek-text-muted);\n margin-left: 2px;\n font-size: 0.95em;\n}\n\n.thek-indicators {\n display: flex;\n align-items: center;\n padding-left: 12px;\n color: var(--thek-text-muted);\n}\n\n.thek-arrow {\n font-size: 0.8em;\n transition: transform 0.2s ease;\n}\n\n.thek-open .thek-arrow {\n transform: rotate(180deg);\n}\n\n.thek-selection {\n display: flex;\n flex-wrap: nowrap;\n overflow: hidden;\n gap: 6px;\n flex: 1;\n -webkit-mask-image: linear-gradient(to right, black 90%, transparent 100%);\n mask-image: linear-gradient(to right, black 90%, transparent 100%);\n}\n\n.thek-summary-text {\n font-size: 0.9em;\n color: var(--thek-text-main);\n white-space: nowrap;\n font-weight: 500;\n}\n\n.thek-tag {\n flex-shrink: 0;\n background-color: var(--thek-bg-panel);\n border: 1px solid var(--thek-border);\n color: var(--thek-text-main);\n border-radius: calc(var(--thek-border-radius) - 2px);\n padding: 2px 8px;\n font-size: 0.8em;\n display: flex;\n align-items: center;\n gap: 6px;\n font-weight: 500;\n transition: background-color 0.1s;\n}\n\n.thek-tag:hover {\n background-color: var(--thek-bg-subtle);\n}\n\n.thek-tag-remove {\n cursor: pointer;\n color: var(--thek-text-muted);\n font-size: 1.1em;\n line-height: 1;\n}\n\n.thek-tag-remove:hover {\n color: var(--thek-danger);\n}\n\n.thek-dropdown {\n background-color: var(--thek-bg-surface);\n border: 1px solid var(--thek-border);\n border-radius: var(--thek-border-radius);\n box-shadow: var(--thek-shadow);\n overflow: hidden;\n box-sizing: border-box;\n margin-top: 4px;\n animation: thek-fade-in 0.15s ease-out;\n}\n\n@keyframes thek-fade-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.thek-search-wrapper {\n padding: 10px;\n border-bottom: 1px solid var(--thek-border);\n position: relative;\n background-color: var(--thek-bg-surface);\n}\n\n.thek-input {\n width: 100%;\n border: 1px solid var(--thek-border);\n background: var(--thek-bg-surface);\n padding: 8px 12px 8px 34px;\n border-radius: calc(var(--thek-border-radius) - 2px);\n color: var(--thek-text-main);\n outline: none;\n font-size: 0.9em;\n transition: border-color 0.2s;\n}\n\n.thek-input:focus {\n border-color: var(--thek-primary);\n}\n\n.thek-search-icon {\n position: absolute;\n left: 22px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--thek-text-muted);\n font-size: 0.85em;\n}\n\n.thek-options {\n list-style: none;\n margin: 0;\n padding: 6px;\n max-height: 240px;\n overflow-y: auto;\n}\n\n.thek-option {\n padding: var(--thek-item-padding);\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 10px;\n transition: all 0.1s ease;\n color: var(--thek-text-main);\n font-size: 0.95em;\n margin-bottom: 2px;\n}\n\n.thek-option:last-child {\n margin-bottom: 0;\n}\n\n.thek-option:hover {\n background-color: var(--thek-bg-panel);\n}\n\n.thek-option.thek-focused {\n background-color: var(--thek-bg-panel);\n}\n\n.thek-option.thek-selected {\n background-color: var(--thek-primary-light);\n color: var(--thek-primary);\n font-weight: 500;\n}\n\n.thek-checkbox {\n width: 1.2em;\n height: 1.2em;\n border: 1.5px solid var(--thek-border-strong);\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--thek-bg-surface);\n font-size: 0.7em;\n flex-shrink: 0;\n transition: all 0.2s;\n}\n\n.thek-option.thek-selected .thek-checkbox {\n background-color: var(--thek-primary);\n border-color: var(--thek-primary);\n color: var(--thek-text-inverse);\n}\n\n.thek-option.thek-disabled {\n opacity: 0.4;\n cursor: not-allowed;\n background-color: transparent;\n}\n\n.thek-no-results, .thek-loading {\n padding: 20px 12px;\n text-align: center;\n color: var(--thek-text-muted);\n font-size: 0.9em;\n}\n\n.thek-disabled .thek-control {\n background-color: var(--thek-bg-subtle);\n cursor: not-allowed;\n opacity: 0.7;\n border-color: var(--thek-border);\n}\n",document.head.appendChild(e),t=!0}();const a="string"==typeof i?document.querySelector(i):i;if(!a)throw new Error("Element not found");this.originalElement=a,this.id=function(e="thek"){return`${e}-${Math.random().toString(36).substr(2,9)}`}(),this.config=function(e,t,n={}){const i=e instanceof HTMLSelectElement,o={options:i?(a=e,Array.from(a.options).map(e=>({value:e.value,label:e.text,disabled:e.disabled,selected:e.selected}))):t.options||[],multiple:!!i&&e.multiple,searchable:!0,disabled:!!i&&e.disabled,placeholder:"Select...",canCreate:!1,createText:"Create '{%t}'...",height:40,debounce:300,maxSelectedLabels:3,displayField:"label",valueField:"value",maxOptions:null,virtualize:!1,virtualItemHeight:40,virtualOverscan:4,virtualThreshold:80,loadOptions:s,renderOption:e=>e.label,renderSelection:e=>e.label,...n,...t};var a;const r=!(!n.renderOption&&!t.renderOption),l=!(!n.renderSelection&&!t.renderSelection);return r||(o.renderOption=e=>e[o.displayField]),l||(o.renderSelection=e=>e[o.displayField]),o}(this.originalElement,o,d.globalDefaults),this.stateManager=new e(function(e){const t=e.valueField,n=e.options.find(e=>e.selected),s=e.multiple?e.options.filter(e=>e.selected).map(e=>e[t]):n&&t in n?[n[t]]:[],i={};return s.forEach(n=>{const s=e.options.find(e=>e[t]===n);s&&(i[n]=s)}),{options:e.options,selectedValues:s,selectedOptionsByValue:i,isOpen:!1,focusedIndex:-1,inputValue:"",isLoading:!1}}(this.config)),this.renderer=new n(this.config,this.id,{onSelect:e=>this.handleSelect(e),onCreate:e=>this.handleCreate(e),onRemove:e=>this.handleSelect(e),onReorder:(e,t)=>this.handleReorder(e,t)}),this.setupHandleSearch(),this.initialize()}static init(e,t={}){return new d(e,t)}static setDefaults(e){d.globalDefaults={...d.globalDefaults,...e}}static resetDefaults(){d.globalDefaults={}}initialize(){this.renderer.createDom(),this.setupListeners(),this.unsubscribeState=this.stateManager.subscribe(()=>this.render()),this.render(),this.originalElement.parentNode&&(this.originalElement.style.display="none",this.originalElement.parentNode.insertBefore(this.renderer.wrapper,this.originalElement.nextSibling))}setupListeners(){this.renderer.control.addEventListener("click",()=>{this.config.disabled||this.toggleDropdown()}),this.config.searchable&&this.renderer.input.addEventListener("input",e=>{const t=e.target.value;this.stateManager.setState({inputValue:t}),this.handleSearch(t)}),this.renderer.input.addEventListener("keydown",e=>this.handleKeyDown(e)),this.unsubscribeEvents.push(l.onClick(e=>{const t=e;this.renderer.wrapper.contains(t.target)||this.renderer.dropdown.contains(t.target)||this.closeDropdown()})),this.unsubscribeEvents.push(l.onResize(()=>this.renderer.positionDropdown())),this.unsubscribeEvents.push(l.onScroll(()=>this.renderer.positionDropdown()))}handleSearch;setupHandleSearch(){this.handleSearch=function(e,t){let n=null;const s=(...s)=>{null!==n&&clearTimeout(n),n=setTimeout(()=>{n=null,e(...s)},t)};return s.cancel=()=>{null!==n&&(clearTimeout(n),n=null)},s}(async e=>{if(this.emit("search",e),i(this.config))if(e.length>0){const t=++this.remoteRequestId;this.stateManager.setState({isLoading:!0});try{const n=await this.config.loadOptions(e);if(this.isDestroyed||t!==this.remoteRequestId)return;const s=this.stateManager.getState();this.stateManager.setState({options:n,isLoading:!1,focusedIndex:0,selectedOptionsByValue:a(this.config.valueField,s.selectedValues,s.selectedOptionsByValue,n)})}catch{if(this.isDestroyed||t!==this.remoteRequestId)return;this.stateManager.setState({isLoading:!1})}}else this.remoteRequestId++,this.stateManager.setState({options:this.config.options,focusedIndex:-1,isLoading:!1});else this.stateManager.setState({focusedIndex:0})},this.config.debounce)}handleKeyDown(e){const t=this.stateManager.getState(),n=o(this.config,t),s=this.config.displayField;switch(e.key){case"ArrowDown":e.preventDefault(),this.openDropdown();const i=this.config.canCreate&&t.inputValue&&!n.some(e=>e[s].toLowerCase()===t.inputValue.toLowerCase())?n.length:n.length-1;this.stateManager.setState({focusedIndex:Math.min(t.focusedIndex+1,i)});break;case"ArrowUp":e.preventDefault(),this.stateManager.setState({focusedIndex:Math.max(t.focusedIndex-1,0)});break;case"Enter":e.preventDefault(),t.focusedIndex>=0&&t.focusedIndex<n.length?this.handleSelect(n[t.focusedIndex]):this.config.canCreate&&t.inputValue&&t.focusedIndex===n.length&&this.handleCreate(t.inputValue);break;case"Escape":this.closeDropdown();break;case"Backspace":""===t.inputValue&&this.config.multiple&&t.selectedValues.length>0&&this.handleRemoveLastSelection()}}toggleDropdown(){this.stateManager.getState().isOpen?this.closeDropdown():this.openDropdown()}openDropdown(){this.stateManager.getState().isOpen||(this.stateManager.setState({isOpen:!0,focusedIndex:0}),this.renderer.positionDropdown(),this.config.searchable&&(this.focusTimeoutId=setTimeout(()=>{this.isDestroyed||this.renderer.input.focus()},10)),this.emit("open",null))}closeDropdown(){this.stateManager.getState().isOpen&&(this.stateManager.setState({isOpen:!1,focusedIndex:-1,inputValue:""}),this.renderer.input.value="",this.emit("close",null))}handleSelect(e){if(e.disabled)return;const t=this.stateManager.getState(),n=function(e,t,n){const s=e.valueField,i=String(n[s]),o={...t.selectedOptionsByValue};if(e.multiple){if(t.selectedValues.includes(i)){const e=t.selectedValues.filter(e=>e!==i);return delete o[i],{selectedValues:e,selectedOptionsByValue:o,inputValue:"",tagEvent:"tagRemoved",tagOption:n}}const e=[...t.selectedValues,i];return o[i]=n,{selectedValues:e,selectedOptionsByValue:o,inputValue:"",tagEvent:"tagAdded",tagOption:n}}return{selectedValues:[i],selectedOptionsByValue:{[i]:n},inputValue:""}}(this.config,t,e);this.config.multiple||this.closeDropdown(),this.stateManager.setState({selectedValues:n.selectedValues,selectedOptionsByValue:n.selectedOptionsByValue,inputValue:""}),this.renderer.input.value="",this.syncOriginalElement(n.selectedValues),n.tagEvent&&n.tagOption&&this.emit(n.tagEvent,n.tagOption),this.emit("change",this.getValue())}handleCreate(e){const t=function(e,t){const n=t;return{value:n,label:t,[e.valueField]:n,[e.displayField]:t}}(this.config,e),n=this.stateManager.getState();this.stateManager.setState({options:[...n.options,t]}),this.handleSelect(t)}handleRemoveLastSelection(){const e=this.stateManager.getState(),t=function(e,t){const n=e.valueField,s=[...t.selectedValues],i={...t.selectedOptionsByValue},o=s.pop();if(!o)return{selectedValues:s,selectedOptionsByValue:i};const a=t.options.find(e=>e[n]===o)||i[o];return delete i[o],{selectedValues:s,selectedOptionsByValue:i,removedOption:a}}(this.config,e);this.stateManager.setState({selectedValues:t.selectedValues,selectedOptionsByValue:t.selectedOptionsByValue}),this.syncOriginalElement(t.selectedValues),t.removedOption&&this.emit("tagRemoved",t.removedOption),this.emit("change",this.getValue())}handleReorder(e,t){const n=function(e,t,n){if(!Number.isInteger(t)||!Number.isInteger(n))return[...e.selectedValues];if(t<0||n<0||t>=e.selectedValues.length||n>=e.selectedValues.length||t===n)return[...e.selectedValues];const s=[...e.selectedValues],[i]=s.splice(t,1);return void 0===i?[...e.selectedValues]:(s.splice(n,0,i),s)}(this.stateManager.getState(),e,t);this.stateManager.setState({selectedValues:n}),this.syncOriginalElement(n),this.emit("reordered",n),this.emit("change",this.getValue())}syncOriginalElement(e){if(this.originalElement instanceof HTMLSelectElement){const t=this.originalElement;Array.from(t.options).forEach(t=>{t.selected=e.includes(t.value)}),e.forEach(e=>{if(!Array.from(t.options).some(t=>t.value===e)){const n=new Option(e,e,!0,!0);t.add(n)}}),t.dispatchEvent(new Event("change",{bubbles:!0}))}}render(){this.renderer.render(this.stateManager.getState(),o(this.config,this.stateManager.getState()))}on(e,t){return this.events.on(e,t)}emit(e,t){this.events.emit(e,t)}getValue(){const e=this.stateManager.getState();return this.config.multiple?e.selectedValues:e.selectedValues[0]}getSelectedOptions(){const e=function(e,t){const n=e.valueField,s=e.displayField;return t.selectedValues.map(e=>t.options.find(t=>t[n]===e)||t.selectedOptionsByValue[e]||{value:e,label:e,[n]:e,[s]:e})}(this.config,this.stateManager.getState());return this.config.multiple?e:e[0]}setValue(e,t=!1){const n=this.stateManager.getState(),s=(Array.isArray(e)?e:[e]).filter(e=>"string"==typeof e),i=this.config.multiple?Array.from(new Set(s)):s.slice(0,1),o=function(e,t,n){const s=e.valueField,i={};return n.forEach(e=>{const n=t.options.find(t=>t[s]===e)||t.selectedOptionsByValue[e];n&&(i[e]=n)}),i}(this.config,n,i);this.stateManager.setState({selectedValues:i,selectedOptionsByValue:o}),this.syncOriginalElement(i),t||this.emit("change",this.getValue())}setHeight(e){this.config.height=e,this.renderer.setHeight(e),this.renderer.positionDropdown()}setRenderOption(e){this.config.renderOption=e,this.renderer.updateConfig({renderOption:e}),this.render()}setMaxOptions(e){this.config.maxOptions=e,this.render()}destroy(){this.isDestroyed=!0,this.remoteRequestId++,this.handleSearch.cancel(),null!==this.focusTimeoutId&&(clearTimeout(this.focusTimeoutId),this.focusTimeoutId=null),this.unsubscribeState&&(this.unsubscribeState(),this.unsubscribeState=void 0),this.unsubscribeEvents.forEach(e=>e()),this.unsubscribeEvents=[],this.renderer.destroy(),this.originalElement.style.display=""}};export{d as ThekSelect};
|