treeselectjs 0.2.5 → 0.2.6

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/README.md CHANGED
@@ -97,7 +97,7 @@ Name | Type (default) | Discription
97
97
  ------------- | ------------- | -------------
98
98
  parentHtmlContainer | HTMLElement | It sould be a HTML element (div), it will be changed to the list container.
99
99
  value | Array[String] ([]) | It is an array with ids.
100
- options | Array[Object] ([]) | It is an array of objects { name: String, value: String, children: [] }, where children are the same array of objects.
100
+ options | Array[Object] ([]) | It is an array of objects { name: String, value: String, children: [] }, where children are the same array of objects. Do not use duplicated values.
101
101
  openLevel | Number (0) | All groups will be opened to this level.
102
102
  appendToBody | Boolean (false) | List will be appended to the body instead of the input container.
103
103
  alwaysOpen | Boolean (false) | List will be always opened.
@@ -119,11 +119,13 @@ input | Array[String] | Returns selected ids without groups, only leafs.
119
119
  Name | Params | Discription
120
120
  ------------- | ------------- | -------------
121
121
  updateValue | Array[String] | Update selected values.
122
- mount | None | Helps to remount and update settings.
123
- destroy | None | Deletes elements from the DOM and clears all the data. Call mount() to recreate.
122
+ mount | None | Helps to remount and update settings. Change settings that you need (treeselect.appendToBody = true), then call mount().
123
+ destroy | None | Deletes elements from the DOM. Call mount() to add treeselect to the DOM with previously saved internal data. If you need to recreate treeselect with default params - call **new Treeselect(options)**.
124
124
 
125
125
  ### Notes
126
126
  1) If you want to change the padding of the element you can use CSS selector. I've added **'group'** and **'level'** attributes, but you have to use **!important**.
127
127
  2) If you want to update props, set props to the entity of the class and then call **mount()** method.
128
128
  3) Use **updateValue()** method to update only the value.
129
- 4) If you need to delete List from the DOM when you don't need treeselect anymore - call **destroy()**.
129
+ 4) If you need to delete List from the DOM when you don't need treeselect anymore - call **destroy()**.
130
+ 5) Do not use **duplicated** values for the options. You will see a error with duplicated values.
131
+ 6) **Value** inside the **options** prop should be a **String**.
package/dist/list.css CHANGED
@@ -1,7 +1,7 @@
1
1
  .treeselect-list{width:100%;box-sizing:border-box;border:1px solid #d7dde4;overflow-y:auto;background-color:#fff;max-height:300px}
2
2
  .treeselect-list__group-container{box-sizing:border-box}.treeselect-list__item{display:flex;align-items:center;box-sizing:border-box;cursor:pointer;height:30px}
3
- .treeselect-list__item--focused{background-color:#f0ffff !important}.treeselect-list__item--hidden{display:none}
4
- .treeselect-list__item-icon{display:flex;align-items:center;cursor:pointer;height:20px;width:20px;min-width:20px}
3
+ .treeselect-list__item:focus{outline:0}.treeselect-list__item--focused{background-color:#f0ffff !important}
4
+ .treeselect-list__item--hidden{display:none}.treeselect-list__item-icon{display:flex;align-items:center;cursor:pointer;height:20px;width:20px;min-width:20px}
5
5
  .treeselect-list__item-icon svg{pointer-events:none;width:100%;height:100%;stroke:#c5c7cb}
6
6
  .treeselect-list__item-icon:hover svg{stroke:#838790}.treeselect-list__item-checkbox-container{width:20px;height:20px;min-width:20px;border:1px solid #d7dde4;border-radius:3px;position:relative;background-color:#fff;pointer-events:none;box-sizing:border-box}
7
7
  .treeselect-list__item-checkbox-container svg{position:absolute;height:100%;width:100%}
package/dist/list.js CHANGED
@@ -1 +1 @@
1
- import svg from"./svgIcons.js";const getFlatOptons=(e,i,l=0,c=0)=>e.reduce((e,t)=>{var s=!!t.children?.length;return e.push({id:t.value,name:t.name,childOf:l,isGroup:s,checked:!1,level:c,isClosed:i<=c&&s,hidden:i<c}),s&&(s=getFlatOptons(t.children,i,t.value,c+1),e.push(...s)),e},[]),checkAllChildrenInputs=({id:t,checked:s},i)=>{i.forEach(e=>{e.childOf===t&&(e.checked=s,e.isGroup&&checkAllChildrenInputs(e,i))})},checkAllParentInputs=(t,e)=>{const s=e.find(e=>e.id===t),i=e.filter(e=>e.childOf===s.id);var l=i.every(e=>e.checked),c=i.some(e=>e.isPartialChecked||e.checked)&&!l,r=!l&&!c;l&&(s.checked=!0,s.isPartialChecked=!1),c&&(s.checked=!1,s.isPartialChecked=!0),r&&(s.checked=!1,s.isPartialChecked=!1),s.childOf&&checkAllParentInputs(s.childOf,e)},checkInput=({id:e,isGroup:t,childOf:s,checked:i},l)=>{t&&checkAllChildrenInputs({id:e,checked:i},l),s&&checkAllParentInputs(s,l)},updateValue=(t,s,e)=>{s.forEach(e=>e.checked=!1);const i=s.filter(e=>t.includes(e.id));i.forEach(e=>{e.checked=!0,e.isPartialChecked=!1,checkInput(e,s)}),updateDOM(s,e)},hideShowChildren=(t,{id:s,isClosed:i})=>{const e=t.filter(e=>e.childOf===s);e.forEach(e=>{e.hidden=i,e.isGroup&&!e.isClosed&&hideShowChildren(t,{id:e.id,isClosed:i})})},updateDOM=(l,c)=>{l.forEach(e=>{const t=c.querySelector(`[input-id="${e.id}"]`),s=getListItemByCheckbox(t);if(t.checked=e.checked,e.checked?s.classList.add("treeselect-list__item--checked"):s.classList.remove("treeselect-list__item--checked"),e.isPartialChecked?s.classList.add("treeselect-list__item--partial-checked"):s.classList.remove("treeselect-list__item--partial-checked"),e.isGroup){const i=s.querySelector(".treeselect-list__item-icon");e.isClosed?(s.classList.add("treeselect-list__item--closed"),i.innerHTML=svg.arrowRight):(s.classList.remove("treeselect-list__item--closed"),i.innerHTML=svg.arrowDown)}e.hidden?s.classList.add("treeselect-list__item--hidden"):s.classList.remove("treeselect-list__item--hidden"),updateLeftPaddingItems(e,s,l),updateCheckboxClasses(e,t)});var e=l.some(e=>!e.hidden);const t=c.querySelector(".treeselect-list__empty");e?t.classList.add("treeselect-list__empty--hidden"):t.classList.remove("treeselect-list__empty--hidden")},updateLeftPaddingItems=(t,e,s)=>{0===t.level?(s=s.some(e=>e.isGroup&&e.level===t.level),s=!t.isGroup&&s?"20px":"5px",e.style.paddingLeft=t.isGroup?"0":s):e.style.paddingLeft=t.isGroup?20*t.level+"px":20*t.level+20+"px",e.setAttribute("level",t.level),e.setAttribute("group",t.isGroup)},updateCheckboxClasses=(e,t)=>{const s=t.parentNode,i=s.querySelector(".treeselect-list__item-checkbox-icon");e.checked?i.innerHTML=svg.check:e.isPartialChecked?i.innerHTML=svg.partialCheck:i.innerHTML=""},getAllFlattedChildren=(s,i)=>i.reduce((e,t)=>(t.childOf===s&&(e.push(t),t.isGroup&&e.push(...getAllFlattedChildren(t.id,i))),e),[]),getAllFlattendParents=(s,i)=>i.reduce((e,t)=>(t.id===s&&(e.push(t),t.childOf&&e.push(...getAllFlattendParents(t.childOf,i))),e),[]),getGroupedValues=e=>{const{onlyGroupsIds:t,allItems:s}=e.reduce((e,t)=>(t.checked&&(t.isGroup&&e.onlyGroupsIds.push(t.id),e.allItems.push(t)),e),{onlyGroupsIds:[],allItems:[]});return s.filter(e=>!t.includes(e.childOf))},getCheckedValues=e=>e.filter(e=>e.checked&&!e.isGroup),getListItemByCheckbox=e=>{return e.parentNode.parentNode};class TreeselectList{#lastFocusedItem=null;#isMouseActionsAvailable=!0;constructor({options:e,value:t,openLevel:s,listSlotHtmlComponent:i,emptyText:l}){this.options=e,this.value=t,this.searchText="",this.openLevel=s??0,this.listSlotHtmlComponent=i,this.emptyText=l??"No results found...",this.flattedOptions=getFlatOptons(this.options,this.openLevel),this.flattedOptionsBeforeSearch=this.flattedOptions,this.selectedNodes={ids:[],groupedIds:[]},this.srcElement=this.#createList(),this.updateValue(this.value)}updateValue(e){updateValue(e,this.flattedOptions,this.srcElement),this.#updateSelectedNodes()}updateSearchValue(i){var e=""===this.searchText&&""!==i;if(this.searchText=i,e&&(this.flattedOptionsBeforeSearch=JSON.parse(JSON.stringify(this.flattedOptions))),""===this.searchText)return this.flattedOptions=this.flattedOptionsBeforeSearch.map(t=>{const e=this.flattedOptions.find(e=>e.id===t.id);return e.isClosed=t.isClosed,e.hidden=t.hidden,e}),this.flattedOptionsBeforeSearch=[],updateDOM(this.flattedOptions,this.srcElement),void this.focusFirstListElement();const s=this.flattedOptions.reduce((e,t)=>{var s;return t.name.toLowerCase().includes(i.toLowerCase())&&(e.push(t),t.isGroup&&(s=getAllFlattedChildren(t.id,this.flattedOptions),e.push(...s)),t.childOf&&(s=getAllFlattendParents(t.childOf,this.flattedOptions),e.push(...s))),e},[]);this.flattedOptions.forEach(t=>{s.some(e=>e.id===t.id)?(t.isGroup&&(t.isClosed=!1,hideShowChildren(this.flattedOptions,t)),t.hidden=!1):t.hidden=!0}),updateDOM(this.flattedOptions,this.srcElement),this.focusFirstListElement()}callKeyAction(e){this.#isMouseActionsAvailable=!1;const t=this.srcElement.querySelector(".treeselect-list__item--focused");if("Enter"===e&&t&&t.dispatchEvent(new Event("mousedown")),"ArrowLeft"===e||"ArrowRight"===e){if(!t)return;const c=t.querySelector(".treeselect-list__item-checkbox"),r=c.getAttribute("input-id");var s=this.flattedOptions.find(e=>e.id===r);const o=t.querySelector(".treeselect-list__item-icon");"ArrowLeft"!==e||s.isClosed||o.dispatchEvent(new Event("mousedown")),"ArrowRight"===e&&s.isClosed&&o.dispatchEvent(new Event("mousedown"))}if("ArrowDown"===e||"ArrowUp"===e){const d=Array.from(this.srcElement.querySelectorAll(".treeselect-list__item-checkbox")).filter(e=>"none"!==window.getComputedStyle(getListItemByCheckbox(e)).display);if(d.length)if(t){s=d.findIndex(e=>getListItemByCheckbox(e).classList.contains("treeselect-list__item--focused"));const n=getListItemByCheckbox(d[s]);n.classList.remove("treeselect-list__item--focused");var s="ArrowDown"===e?s+1:s-1,i="ArrowDown"===e?0:d.length-1,i=d[s]??d[i],s=!d[s];const a=getListItemByCheckbox(i);a.classList.add("treeselect-list__item--focused");var i=this.srcElement.getBoundingClientRect(),l=a.getBoundingClientRect();s&&"ArrowDown"===e?this.srcElement.scroll(0,0):s&&"ArrowUp"===e?this.srcElement.scroll(0,this.srcElement.scrollHeight):i.y+i.height<l.y+l.height?this.srcElement.scroll(0,this.srcElement.scrollTop+l.height):i.y>l.y&&this.srcElement.scroll(0,this.srcElement.scrollTop-l.height)}else{const h=getListItemByCheckbox(d[0]);h.classList.add("treeselect-list__item--focused")}}}focusFirstListElement(){var e="treeselect-list__item--focused";const t=this.srcElement.querySelector("."+e);var s=Array.from(this.srcElement.querySelectorAll(".treeselect-list__item-checkbox")).filter(e=>"none"!==window.getComputedStyle(getListItemByCheckbox(e)).display);if(s.length){t&&t.classList.remove(e);const i=getListItemByCheckbox(s[0]);i.classList.add(e)}}#createList(){const e=[],t=document.createElement("div");t.classList.add("treeselect-list");var s=this.#getListHTML(this.options);if(e.push(...s),this.listSlotHtmlComponent){const i=document.createElement("div");i.classList.add("treeselect-list__slot"),i.appendChild(this.listSlotHtmlComponent),e.push(i)}s=this.#createEmptyList();return e.push(s),t.addEventListener("mouseout",e=>{e.stopPropagation(),this.#lastFocusedItem&&this.#isMouseActionsAvailable&&this.#lastFocusedItem.classList.add("treeselect-list__item--focused")}),t.addEventListener("mousemove",()=>{this.#isMouseActionsAvailable=!0}),t.append(...e),t}#getListHTML(e){return e.reduce((e,t)=>{if(t.children?.length){const i=this.#createGroupContainer(t);var s=this.#getListHTML(t.children);return i.append(...s),e.push(i),e}s=this.#createGroupItem(t,!1);return e.push(s),e},[])}#createGroupContainer(e){const t=document.createElement("div");t.setAttribute("group-container-id",e.value),t.classList.add("treeselect-list__group-container");e=this.#createGroupItem(e,!0);return t.appendChild(e),t}#createGroupItem(s,e){const t=document.createElement("div");t.setAttribute("tabindex","-1"),t.setAttribute("title",s.name),t.classList.add("treeselect-list__item"),e&&(e=this.#createArrow(),t.appendChild(e)),t.addEventListener("mouseover",()=>{this.#isMouseActionsAvailable&&this.#groupMouseAction(!0,t)},!0),t.addEventListener("mouseout",()=>{this.#isMouseActionsAvailable&&(this.#groupMouseAction(!1,t),this.#lastFocusedItem=t)},!0),t.addEventListener("mousedown",e=>{e.stopPropagation();const t=e.target.querySelector(".treeselect-list__item-checkbox");t.checked=!t.checked,this.#checkboxClickEvent(t,s)});var e=this.#createCheckbox(s),i=this.#createCheckboxLabel(s);return t.append(e,i),t}#createArrow(){const e=document.createElement("span");return e.setAttribute("tabindex","-1"),e.classList.add("treeselect-list__item-icon"),e.innerHTML=svg.arrowDown,e.addEventListener("mousedown",e=>{e.stopPropagation(),this.#arrowClickEvent(e)}),e}#createCheckbox(e){const t=document.createElement("div"),s=(t.classList.add("treeselect-list__item-checkbox-container"),document.createElement("span")),i=(s.classList.add("treeselect-list__item-checkbox-icon"),s.innerHTML="",document.createElement("input"));return i.setAttribute("tabindex","-1"),i.setAttribute("type","checkbox"),i.setAttribute("input-id",e.value),i.classList.add("treeselect-list__item-checkbox"),t.append(s,i),t}#createCheckboxLabel(e){const t=document.createElement("label");return t.innerHTML=e.name,t.classList.add("treeselect-list__item-label"),t}#createEmptyList(){const e=document.createElement("div"),t=(e.classList.add("treeselect-list__empty"),e.setAttribute("title",this.emptyText),document.createElement("span")),s=(t.classList.add("treeselect-list__empty-icon"),t.innerHTML=svg.attention,document.createElement("span"));return s.classList.add("treeselect-list__empty-text"),s.innerHTML=this.emptyText,e.append(t,s),e}#checkboxClickEvent(e,t){const s=this.flattedOptions.find(e=>e.id===t.value);s.checked=e.checked,s.isPartialChecked=!1,checkInput(s,this.flattedOptions),updateDOM(this.flattedOptions,this.srcElement),this.#emitInput()}#arrowClickEvent(e){const t=e.target.parentNode.querySelector("[input-id]"),s=t.getAttribute("input-id"),i=this.flattedOptions.find(e=>e.id===s);i.isClosed=!i.isClosed,hideShowChildren(this.flattedOptions,i),updateDOM(this.flattedOptions,this.srcElement),this.#emitArrrowClick()}#groupMouseAction(e,t){const s="treeselect-list__item--focused";if(e){const i=Array.from(this.srcElement.querySelectorAll("."+s));i.length&&i.forEach(e=>e.classList.remove(s)),t.classList.add(s)}else t.classList.remove(s)}#updateSelectedNodes(){this.selectedNodes={ids:getCheckedValues(this.flattedOptions),groupedIds:getGroupedValues(this.flattedOptions)}}#emitArrrowClick(){this.srcElement.dispatchEvent(new CustomEvent("arrow-click"))}#emitInput(){this.#updateSelectedNodes(),this.srcElement.dispatchEvent(new CustomEvent("input",{detail:this.selectedNodes}))}}export default TreeselectList;
1
+ import svg from"./svgIcons.js";const getFlatOptons=(e,i,l=0,c=0)=>e.reduce((e,t)=>{var s=!!t.children?.length;return e.push({id:t.value,name:t.name,childOf:l,isGroup:s,checked:!1,level:c,isClosed:i<=c&&s,hidden:i<c}),s&&(s=getFlatOptons(t.children,i,t.value,c+1),e.push(...s)),e},[]),checkAllChildrenInputs=({id:t,checked:s},i)=>{i.forEach(e=>{e.childOf===t&&(e.checked=s,e.isGroup&&checkAllChildrenInputs(e,i))})},checkAllParentInputs=(t,e)=>{const s=e.find(e=>e.id===t),i=e.filter(e=>e.childOf===s.id);var l=i.every(e=>e.checked),c=i.some(e=>e.isPartialChecked||e.checked)&&!l,r=!l&&!c;l&&(s.checked=!0,s.isPartialChecked=!1),c&&(s.checked=!1,s.isPartialChecked=!0),r&&(s.checked=!1,s.isPartialChecked=!1),s.childOf&&checkAllParentInputs(s.childOf,e)},checkInput=({id:e,isGroup:t,childOf:s,checked:i},l)=>{t&&checkAllChildrenInputs({id:e,checked:i},l),s&&checkAllParentInputs(s,l)},updateValue=(t,s,e)=>{s.forEach(e=>{e.checked=!1,e.isPartialChecked=!1});const i=s.filter(e=>t.includes(e.id));i.forEach(e=>{e.checked=!0,e.isPartialChecked=!1,checkInput(e,s)}),updateDOM(s,e)},hideShowChildren=(t,{id:s,isClosed:i})=>{const e=t.filter(e=>e.childOf===s);e.forEach(e=>{e.hidden=i,e.isGroup&&!e.isClosed&&hideShowChildren(t,{id:e.id,isClosed:i})})},updateDOM=(l,c)=>{l.forEach(e=>{const t=c.querySelector(`[input-id="${e.id}"]`),s=getListItemByCheckbox(t);if(t.checked=e.checked,e.checked?s.classList.add("treeselect-list__item--checked"):s.classList.remove("treeselect-list__item--checked"),e.isPartialChecked?s.classList.add("treeselect-list__item--partial-checked"):s.classList.remove("treeselect-list__item--partial-checked"),e.isGroup){const i=s.querySelector(".treeselect-list__item-icon");e.isClosed?(s.classList.add("treeselect-list__item--closed"),i.innerHTML=svg.arrowRight):(s.classList.remove("treeselect-list__item--closed"),i.innerHTML=svg.arrowDown)}e.hidden?s.classList.add("treeselect-list__item--hidden"):s.classList.remove("treeselect-list__item--hidden"),updateLeftPaddingItems(e,s,l),updateCheckboxClasses(e,t)});var e=l.some(e=>!e.hidden);const t=c.querySelector(".treeselect-list__empty");e?t.classList.add("treeselect-list__empty--hidden"):t.classList.remove("treeselect-list__empty--hidden")},updateLeftPaddingItems=(t,e,s)=>{0===t.level?(s=s.some(e=>e.isGroup&&e.level===t.level),s=!t.isGroup&&s?"20px":"5px",e.style.paddingLeft=t.isGroup?"0":s):e.style.paddingLeft=t.isGroup?20*t.level+"px":20*t.level+20+"px",e.setAttribute("level",t.level),e.setAttribute("group",t.isGroup)},updateCheckboxClasses=(e,t)=>{const s=t.parentNode,i=s.querySelector(".treeselect-list__item-checkbox-icon");e.checked?i.innerHTML=svg.check:e.isPartialChecked?i.innerHTML=svg.partialCheck:i.innerHTML=""},getAllFlattedChildren=(s,i)=>i.reduce((e,t)=>(t.childOf===s&&(e.push(t),t.isGroup&&e.push(...getAllFlattedChildren(t.id,i))),e),[]),getAllFlattendParents=(s,i)=>i.reduce((e,t)=>(t.id===s&&(e.push(t),t.childOf&&e.push(...getAllFlattendParents(t.childOf,i))),e),[]),getGroupedValues=e=>{const{onlyGroupsIds:t,allItems:s}=e.reduce((e,t)=>(t.checked&&(t.isGroup&&e.onlyGroupsIds.push(t.id),e.allItems.push(t)),e),{onlyGroupsIds:[],allItems:[]});return s.filter(e=>!t.includes(e.childOf))},getCheckedValues=e=>e.filter(e=>e.checked&&!e.isGroup),getListItemByCheckbox=e=>{return e.parentNode.parentNode},validateOptions=e=>{const t=e.reduce((e,t)=>(e.allItems.includes(t.id)&&e.duplications.push(t.id),e.allItems.push(t.id),e),{duplications:[],allItems:[]})["duplications"];t.length&&console.error(`You have duplicated values: ${t.join(", ")}! You should use unique values.`)};class TreeselectList{#lastFocusedItem=null;#isMouseActionsAvailable=!0;constructor({options:e,value:t,openLevel:s,listSlotHtmlComponent:i,emptyText:l}){this.options=e,this.value=t,this.searchText="",this.openLevel=s??0,this.listSlotHtmlComponent=i,this.emptyText=l??"No results found...",this.flattedOptions=getFlatOptons(this.options,this.openLevel),this.flattedOptionsBeforeSearch=this.flattedOptions,this.selectedNodes={ids:[],groupedIds:[]},this.srcElement=this.#createList(),this.updateValue(this.value),validateOptions(this.flattedOptions)}updateValue(e){updateValue(e,this.flattedOptions,this.srcElement),this.#updateSelectedNodes()}updateSearchValue(i){var e=""===this.searchText&&""!==i;if(this.searchText=i,e&&(this.flattedOptionsBeforeSearch=JSON.parse(JSON.stringify(this.flattedOptions))),""===this.searchText)return this.flattedOptions=this.flattedOptionsBeforeSearch.map(t=>{const e=this.flattedOptions.find(e=>e.id===t.id);return e.isClosed=t.isClosed,e.hidden=t.hidden,e}),this.flattedOptionsBeforeSearch=[],updateDOM(this.flattedOptions,this.srcElement),void this.focusFirstListElement();const s=this.flattedOptions.reduce((e,t)=>{var s;return t.name.toLowerCase().includes(i.toLowerCase())&&(e.push(t),t.isGroup&&(s=getAllFlattedChildren(t.id,this.flattedOptions),e.push(...s)),t.childOf&&(s=getAllFlattendParents(t.childOf,this.flattedOptions),e.push(...s))),e},[]);this.flattedOptions.forEach(t=>{s.some(e=>e.id===t.id)?(t.isGroup&&(t.isClosed=!1,hideShowChildren(this.flattedOptions,t)),t.hidden=!1):t.hidden=!0}),updateDOM(this.flattedOptions,this.srcElement),this.focusFirstListElement()}callKeyAction(e){this.#isMouseActionsAvailable=!1;const t=this.srcElement.querySelector(".treeselect-list__item--focused");if("Enter"===e&&t&&t.dispatchEvent(new Event("mousedown")),"ArrowLeft"===e||"ArrowRight"===e){if(!t)return;const c=t.querySelector(".treeselect-list__item-checkbox"),r=c.getAttribute("input-id");var s=this.flattedOptions.find(e=>e.id===r);const o=t.querySelector(".treeselect-list__item-icon");"ArrowLeft"!==e||s.isClosed||o.dispatchEvent(new Event("mousedown")),"ArrowRight"===e&&s.isClosed&&o.dispatchEvent(new Event("mousedown"))}if("ArrowDown"===e||"ArrowUp"===e){const d=Array.from(this.srcElement.querySelectorAll(".treeselect-list__item-checkbox")).filter(e=>"none"!==window.getComputedStyle(getListItemByCheckbox(e)).display);if(d.length)if(t){s=d.findIndex(e=>getListItemByCheckbox(e).classList.contains("treeselect-list__item--focused"));const n=getListItemByCheckbox(d[s]);n.classList.remove("treeselect-list__item--focused");var s="ArrowDown"===e?s+1:s-1,i="ArrowDown"===e?0:d.length-1,i=d[s]??d[i],s=!d[s];const a=getListItemByCheckbox(i);a.classList.add("treeselect-list__item--focused");var i=this.srcElement.getBoundingClientRect(),l=a.getBoundingClientRect();s&&"ArrowDown"===e?this.srcElement.scroll(0,0):s&&"ArrowUp"===e?this.srcElement.scroll(0,this.srcElement.scrollHeight):i.y+i.height<l.y+l.height?this.srcElement.scroll(0,this.srcElement.scrollTop+l.height):i.y>l.y&&this.srcElement.scroll(0,this.srcElement.scrollTop-l.height)}else{const h=getListItemByCheckbox(d[0]);h.classList.add("treeselect-list__item--focused")}}}focusFirstListElement(){var e="treeselect-list__item--focused";const t=this.srcElement.querySelector("."+e);var s=Array.from(this.srcElement.querySelectorAll(".treeselect-list__item-checkbox")).filter(e=>"none"!==window.getComputedStyle(getListItemByCheckbox(e)).display);if(s.length){t&&t.classList.remove(e);const i=getListItemByCheckbox(s[0]);i.classList.add(e)}}#createList(){const e=[],t=document.createElement("div");t.classList.add("treeselect-list");var s=this.#getListHTML(this.options);if(e.push(...s),this.listSlotHtmlComponent){const i=document.createElement("div");i.classList.add("treeselect-list__slot"),i.appendChild(this.listSlotHtmlComponent),e.push(i)}s=this.#createEmptyList();return e.push(s),t.addEventListener("mouseout",e=>{e.stopPropagation(),this.#lastFocusedItem&&this.#isMouseActionsAvailable&&this.#lastFocusedItem.classList.add("treeselect-list__item--focused")}),t.addEventListener("mousemove",()=>{this.#isMouseActionsAvailable=!0}),t.append(...e),t}#getListHTML(e){return e.reduce((e,t)=>{if(t.children?.length){const i=this.#createGroupContainer(t);var s=this.#getListHTML(t.children);return i.append(...s),e.push(i),e}s=this.#createGroupItem(t,!1);return e.push(s),e},[])}#createGroupContainer(e){const t=document.createElement("div");t.setAttribute("group-container-id",e.value),t.classList.add("treeselect-list__group-container");e=this.#createGroupItem(e,!0);return t.appendChild(e),t}#createGroupItem(s,e){const t=document.createElement("div");t.setAttribute("tabindex","-1"),t.setAttribute("title",s.name),t.classList.add("treeselect-list__item"),e&&(e=this.#createArrow(),t.appendChild(e)),t.addEventListener("mouseover",()=>{this.#isMouseActionsAvailable&&this.#groupMouseAction(!0,t)},!0),t.addEventListener("mouseout",()=>{this.#isMouseActionsAvailable&&(this.#groupMouseAction(!1,t),this.#lastFocusedItem=t)},!0),t.addEventListener("mousedown",e=>{e.stopPropagation();const t=e.target.querySelector(".treeselect-list__item-checkbox");t.checked=!t.checked,this.#checkboxClickEvent(t,s)});var e=this.#createCheckbox(s),i=this.#createCheckboxLabel(s);return t.append(e,i),t}#createArrow(){const e=document.createElement("span");return e.setAttribute("tabindex","-1"),e.classList.add("treeselect-list__item-icon"),e.innerHTML=svg.arrowDown,e.addEventListener("mousedown",e=>{e.stopPropagation(),this.#arrowClickEvent(e)}),e}#createCheckbox(e){const t=document.createElement("div"),s=(t.classList.add("treeselect-list__item-checkbox-container"),document.createElement("span")),i=(s.classList.add("treeselect-list__item-checkbox-icon"),s.innerHTML="",document.createElement("input"));return i.setAttribute("tabindex","-1"),i.setAttribute("type","checkbox"),i.setAttribute("input-id",e.value),i.classList.add("treeselect-list__item-checkbox"),t.append(s,i),t}#createCheckboxLabel(e){const t=document.createElement("label");return t.innerHTML=e.name,t.classList.add("treeselect-list__item-label"),t}#createEmptyList(){const e=document.createElement("div"),t=(e.classList.add("treeselect-list__empty"),e.setAttribute("title",this.emptyText),document.createElement("span")),s=(t.classList.add("treeselect-list__empty-icon"),t.innerHTML=svg.attention,document.createElement("span"));return s.classList.add("treeselect-list__empty-text"),s.innerHTML=this.emptyText,e.append(t,s),e}#checkboxClickEvent(e,t){const s=this.flattedOptions.find(e=>e.id===t.value);s.checked=e.checked,s.isPartialChecked=!1,checkInput(s,this.flattedOptions),updateDOM(this.flattedOptions,this.srcElement),this.#emitInput()}#arrowClickEvent(e){const t=e.target.parentNode.querySelector("[input-id]"),s=t.getAttribute("input-id"),i=this.flattedOptions.find(e=>e.id===s);i.isClosed=!i.isClosed,hideShowChildren(this.flattedOptions,i),updateDOM(this.flattedOptions,this.srcElement),this.#emitArrrowClick()}#groupMouseAction(e,t){const s="treeselect-list__item--focused";if(e){const i=Array.from(this.srcElement.querySelectorAll("."+s));i.length&&i.forEach(e=>e.classList.remove(s)),t.classList.add(s)}else t.classList.remove(s)}#updateSelectedNodes(){this.selectedNodes={ids:getCheckedValues(this.flattedOptions),groupedIds:getGroupedValues(this.flattedOptions)}}#emitArrrowClick(){this.srcElement.dispatchEvent(new CustomEvent("arrow-click"))}#emitInput(){this.#updateSelectedNodes(),this.srcElement.dispatchEvent(new CustomEvent("input",{detail:this.selectedNodes}))}}export default TreeselectList;
@@ -4,5 +4,5 @@
4
4
  .treeselect-input--opened.treeselect-input--top{border-top-color:transparent;border-top-left-radius:0;border-top-right-radius:0}
5
5
  .treeselect-input--opened.treeselect-input--bottom{border-bottom-color:transparent;border-bottom-left-radius:0;border-bottom-right-radius:0}
6
6
  .treeselect-list--focused{border-color:#101010}.treeselect-list--top,.treeselect-list--top-to-body{border-bottom-color:#d7dde4;border-bottom-left-radius:0;border-bottom-right-radius:0}
7
- .treeselect-list--bottom,.treeselect-list--bottom-to-body{border-top-color:gainsboro;border-top-left-radius:0;border-top-right-radius:0}
7
+ .treeselect-list--bottom,.treeselect-list--bottom-to-body{border-top-color:#d7dde4;border-top-left-radius:0;border-top-right-radius:0}
8
8
  .treeselect-list--top{left:0;bottom:100%}.treeselect-list--bottom{left:0;top:100%}
@@ -1 +1 @@
1
- import TreeselectInput from"./input.js";import TreeselectList from"./list.js";class Treeselect{#htmlContainer=null;#treeselectList=null;#treeselectInput=null;#transform={top:null,bottom:null};#treeselectInitPosition=null;#containerResizer=null;#containerWidth=0;#scrollEvent=null;#focusEvent=null;#blurEvent=null;constructor({parentHtmlContainer:e,value:t,options:s,openLevel:i,appendToBody:n,alwaysOpen:l,showTags:r,clearable:o,searchable:c,placeholder:a,grouped:d,listSlotHtmlComponent:h,disabled:u,emptyText:p}){this.parentHtmlContainer=e,this.value=t??[],this.options=s??[],this.openLevel=i??0,this.appendToBody=n??!0,this.alwaysOpen=l&&!u,this.showTags=r??!0,this.clearable=o??!0,this.searchable=c??!0,this.placeholder=a??"Search...",this.grouped=d??!0,this.listSlotHtmlComponent=h??null,this.disabled=u??!1,this.emptyText=p??"No results found...",this.srcElement=null,this.mount()}mount(){this.srcElement&&(this.#closeList(),this.srcElement.innerHTML="",this.srcElement=null,this.#removeOutsideListeners()),this.srcElement=this.#createTreeselect(),this.#scrollEvent=this.scrollWindowHandler.bind(this),this.#focusEvent=this.focusWindowHandler.bind(this),this.#blurEvent=this.blurWindowHandler.bind(this),this.alwaysOpen&&this.#treeselectInput.openClose(),this.disabled&&this.srcElement.classList.add("treeselect--disabled")}updateValue(e){const t=this.#treeselectList;t.updateValue(e);var{groupedIds:e,ids:s}=t.selectedNodes,e=this.grouped?e:s;this.#treeselectInput.updateValue(e)}destroy(){this.srcElement&&(this.#closeList(),this.srcElement.innerHTML="",this.srcElement=null,this.#removeOutsideListeners())}#createTreeselect(){const t=this.parentHtmlContainer,s=(t.classList.add("treeselect"),new TreeselectList({options:this.options,value:this.value,openLevel:this.openLevel,listSlotHtmlComponent:this.listSlotHtmlComponent,emptyText:this.emptyText}));var{groupedIds:e,ids:i}=s.selectedNodes;const n=new TreeselectInput({value:this.grouped?e:i,showTags:this.showTags,clearable:this.clearable,isAlwaysOpened:this.alwaysOpen,searchable:this.searchable,placeholder:this.placeholder,disabled:this.disabled});return this.appendToBody&&(this.#containerResizer=new ResizeObserver(()=>{var e=this.srcElement.getBoundingClientRect()["width"];this.#containerWidth=e,this.updateListPosition(t,s.srcElement,!0)})),n.srcElement.addEventListener("input",e=>{e=e.detail.map(({id:e})=>e);this.value=e,s.updateValue(e),this.#emitInput()}),n.srcElement.addEventListener("open",()=>this.#openList()),n.srcElement.addEventListener("keydown",e=>s.callKeyAction(e.key)),n.srcElement.addEventListener("search",e=>{s.updateSearchValue(e.detail),this.updateListPosition(t,s.srcElement,!0)}),n.srcElement.addEventListener("focus",()=>{this.#updateFocusClasses(!0),document.addEventListener("mousedown",this.#focusEvent,!0),document.addEventListener("focus",this.#focusEvent,!0),window.addEventListener("blur",this.#blurEvent)},!0),this.alwaysOpen||n.srcElement.addEventListener("close",()=>{this.#closeList()}),s.srcElement.addEventListener("mouseup",()=>{n.focus()},!0),s.srcElement.addEventListener("input",e=>{const{groupedIds:t,ids:s}=e.detail;e=this.grouped?t:s;n.updateValue(e),this.value=s.map(({id:e})=>e),n.focus(),this.#emitInput()}),s.srcElement.addEventListener("arrow-click",()=>{n.focus(),this.updateListPosition(t,s.srcElement,!0)}),this.#htmlContainer=t,this.#treeselectList=s,this.#treeselectInput=n,t.append(n.srcElement),t}#openList(){window.addEventListener("scroll",this.#scrollEvent,!0),this.appendToBody?(document.body.appendChild(this.#treeselectList.srcElement),this.#containerResizer.observe(this.#htmlContainer)):this.#htmlContainer.appendChild(this.#treeselectList.srcElement),this.updateListPosition(this.#htmlContainer,this.#treeselectList.srcElement,!1),this.#updateOpenCloseClasses(!0),this.#treeselectList.focusFirstListElement()}#closeList(){window.removeEventListener("scroll",this.#scrollEvent,!0),(this.appendToBody?document.body:this.#htmlContainer).contains(this.#treeselectList.srcElement)&&(this.appendToBody?(document.body.removeChild(this.#treeselectList.srcElement),this.#containerResizer?.disconnect()):this.#htmlContainer.removeChild(this.#treeselectList.srcElement),this.#updateOpenCloseClasses(!1))}#updateDirectionClasses(e,t){var s=t?"treeselect-list--top-to-body":"treeselect-list--top",t=t?"treeselect-list--bottom-to-body":"treeselect-list--bottom";e?(this.#treeselectList.srcElement.classList.add(s),this.#treeselectList.srcElement.classList.remove(t),this.#treeselectInput.srcElement.classList.add("treeselect-input--top"),this.#treeselectInput.srcElement.classList.remove("treeselect-input--bottom")):(this.#treeselectList.srcElement.classList.remove(s),this.#treeselectList.srcElement.classList.add(t),this.#treeselectInput.srcElement.classList.remove("treeselect-input--top"),this.#treeselectInput.srcElement.classList.add("treeselect-input--bottom"))}#updateFocusClasses(e){e?(this.#treeselectInput.srcElement.classList.add("treeselect-input--focused"),this.#treeselectList.srcElement.classList.add("treeselect-list--focused")):(this.#treeselectInput.srcElement.classList.remove("treeselect-input--focused"),this.#treeselectList.srcElement.classList.remove("treeselect-list--focused"))}#updateOpenCloseClasses(e){e?this.#treeselectInput.srcElement.classList.add("treeselect-input--opened"):this.#treeselectInput.srcElement.classList.remove("treeselect-input--opened")}#removeOutsideListeners(){window.removeEventListener("scroll",this.#scrollEvent,!0),document.removeEventListener("click",this.#focusEvent,!0),document.removeEventListener("focus",this.#focusEvent,!0),window.removeEventListener("blur",this.#blurEvent)}scrollWindowHandler(){this.updateListPosition(this.#htmlContainer,this.#treeselectList.srcElement,!0)}focusWindowHandler(e){this.#htmlContainer.contains(e.target)||this.#treeselectList.srcElement.contains(e.target)||(this.#treeselectInput.blur(),this.#removeOutsideListeners(),this.#updateFocusClasses(!1))}blurWindowHandler(){this.#treeselectInput.blur(),this.#removeOutsideListeners(),this.#updateFocusClasses(!1)}updateListPosition(e,t,s){var i=e.getBoundingClientRect().y,n=window.innerHeight-e.getBoundingClientRect().y,l=t.clientHeight,n=n<i&&window.innerHeight-i<l+45,i=n?"top":"buttom",r=t.getAttribute("direction");if(this.#htmlContainer.setAttribute("direction",i),!this.appendToBody)return r===i?void 0:void this.#updateDirectionClasses(n,!1);if(!this.#treeselectInitPosition||s){t.style.transform=null;const{x:d,y:o}=t.getBoundingClientRect(),{x:c,y:a}=e.getBoundingClientRect();this.#treeselectInitPosition={containerX:c,containerY:a,listX:d,listY:o}}const{listY:o,containerX:c,containerY:a}=this.#treeselectInitPosition;i=e.clientHeight;r&&!s||(this.#transform.top=`translateY(${a-o-l}px)`,this.#transform.bottom=`translateY(${a+i-o}px)`),t.style.transform=n?this.#transform.top:this.#transform.bottom,this.#updateDirectionClasses(n,!0),t.style.width=this.#containerWidth+"px",t.style.left=c+"px"}#emitInput(){this.srcElement.dispatchEvent(new CustomEvent("input",{detail:this.value}))}}export default Treeselect;
1
+ import TreeselectInput from"./input.js";import TreeselectList from"./list.js";class Treeselect{#htmlContainer=null;#treeselectList=null;#treeselectInput=null;#containerResizer=null;#scrollEvent=null;#focusEvent=null;#blurEvent=null;constructor({parentHtmlContainer:e,value:t,options:s,openLevel:i,appendToBody:l,alwaysOpen:n,showTags:r,clearable:o,searchable:c,placeholder:a,grouped:d,listSlotHtmlComponent:h,disabled:u,emptyText:p}){this.parentHtmlContainer=e,this.value=t??[],this.options=s??[],this.openLevel=i??0,this.appendToBody=l??!0,this.alwaysOpen=n&&!u,this.showTags=r??!0,this.clearable=o??!0,this.searchable=c??!0,this.placeholder=a??"Search...",this.grouped=d??!0,this.listSlotHtmlComponent=h??null,this.disabled=u??!1,this.emptyText=p??"No results found...",this.srcElement=null,this.mount()}mount(){this.destroy(),this.srcElement=this.#createTreeselect(),this.#scrollEvent=this.scrollWindowHandler.bind(this),this.#focusEvent=this.focusWindowHandler.bind(this),this.#blurEvent=this.blurWindowHandler.bind(this),this.alwaysOpen&&this.#treeselectInput.openClose(),this.disabled&&this.srcElement.classList.add("treeselect--disabled")}updateValue(e){const t=this.#treeselectList;t.updateValue(e);var{groupedIds:e,ids:s}=t.selectedNodes,e=this.grouped?e:s;this.#treeselectInput.updateValue(e)}destroy(){this.srcElement&&(this.#closeList(),this.srcElement.innerHTML="",this.srcElement=null,this.#removeOutsideListeners(!0))}#createTreeselect(){const e=this.parentHtmlContainer,t=(e.classList.add("treeselect"),new TreeselectList({options:this.options,value:this.value,openLevel:this.openLevel,listSlotHtmlComponent:this.listSlotHtmlComponent,emptyText:this.emptyText}));var{groupedIds:s,ids:i}=t.selectedNodes;const l=new TreeselectInput({value:this.grouped?s:i,showTags:this.showTags,clearable:this.clearable,isAlwaysOpened:this.alwaysOpen,searchable:this.searchable,placeholder:this.placeholder,disabled:this.disabled});return this.appendToBody&&(this.#containerResizer=new ResizeObserver(()=>{this.updateListPosition()})),l.srcElement.addEventListener("input",e=>{e=e.detail.map(({id:e})=>e);this.value=e,t.updateValue(e),this.#emitInput()}),l.srcElement.addEventListener("open",()=>this.#openList()),l.srcElement.addEventListener("keydown",e=>t.callKeyAction(e.key)),l.srcElement.addEventListener("search",e=>{t.updateSearchValue(e.detail),this.updateListPosition()}),l.srcElement.addEventListener("focus",()=>{this.#updateFocusClasses(!0),document.addEventListener("mousedown",this.#focusEvent,!0),document.addEventListener("focus",this.#focusEvent,!0),window.addEventListener("blur",this.#blurEvent)},!0),this.alwaysOpen||l.srcElement.addEventListener("close",()=>{this.#closeList()}),t.srcElement.addEventListener("mouseup",()=>{l.focus()},!0),t.srcElement.addEventListener("input",e=>{const{groupedIds:t,ids:s}=e.detail;e=this.grouped?t:s;l.updateValue(e),this.value=s.map(({id:e})=>e),l.focus(),this.#emitInput()}),t.srcElement.addEventListener("arrow-click",()=>{l.focus(),this.updateListPosition()}),this.#htmlContainer=e,this.#treeselectList=t,this.#treeselectInput=l,e.append(l.srcElement),e}#openList(){window.addEventListener("scroll",this.#scrollEvent,!0),this.appendToBody?(document.body.appendChild(this.#treeselectList.srcElement),this.#containerResizer.observe(this.#htmlContainer)):this.#htmlContainer.appendChild(this.#treeselectList.srcElement),this.updateListPosition(),this.#updateOpenCloseClasses(!0),this.#treeselectList.focusFirstListElement()}#closeList(){window.removeEventListener("scroll",this.#scrollEvent,!0),(this.appendToBody?document.body:this.#htmlContainer).contains(this.#treeselectList.srcElement)&&(this.appendToBody?(document.body.removeChild(this.#treeselectList.srcElement),this.#containerResizer?.disconnect()):this.#htmlContainer.removeChild(this.#treeselectList.srcElement),this.#updateOpenCloseClasses(!1))}#updateDirectionClasses(e,t){var s=t?"treeselect-list--top-to-body":"treeselect-list--top",t=t?"treeselect-list--bottom-to-body":"treeselect-list--bottom";e?(this.#treeselectList.srcElement.classList.add(s),this.#treeselectList.srcElement.classList.remove(t),this.#treeselectInput.srcElement.classList.add("treeselect-input--top"),this.#treeselectInput.srcElement.classList.remove("treeselect-input--bottom")):(this.#treeselectList.srcElement.classList.remove(s),this.#treeselectList.srcElement.classList.add(t),this.#treeselectInput.srcElement.classList.remove("treeselect-input--top"),this.#treeselectInput.srcElement.classList.add("treeselect-input--bottom"))}#updateFocusClasses(e){e?(this.#treeselectInput.srcElement.classList.add("treeselect-input--focused"),this.#treeselectList.srcElement.classList.add("treeselect-list--focused")):(this.#treeselectInput.srcElement.classList.remove("treeselect-input--focused"),this.#treeselectList.srcElement.classList.remove("treeselect-list--focused"))}#updateOpenCloseClasses(e){e?this.#treeselectInput.srcElement.classList.add("treeselect-input--opened"):this.#treeselectInput.srcElement.classList.remove("treeselect-input--opened")}#removeOutsideListeners(e){this.alwaysOpen&&!e||window.removeEventListener("scroll",this.#scrollEvent,!0),document.removeEventListener("click",this.#focusEvent,!0),document.removeEventListener("focus",this.#focusEvent,!0),window.removeEventListener("blur",this.#blurEvent)}scrollWindowHandler(){this.updateListPosition()}focusWindowHandler(e){this.#htmlContainer.contains(e.target)||this.#treeselectList.srcElement.contains(e.target)||(this.#treeselectInput.blur(),this.#removeOutsideListeners(),this.#updateFocusClasses(!1))}blurWindowHandler(){this.#treeselectInput.blur(),this.#removeOutsideListeners(),this.#updateFocusClasses(!1)}updateListPosition(){const e=this.#treeselectList.srcElement,t=(e.style.transform=null,this.#htmlContainer);var{y:s,height:i}=e.getBoundingClientRect(),{x:l,y:n,height:r,width:o}=t.getBoundingClientRect(),c=window.innerHeight-n-r,c=c<n&&i<=n&&c<i,i=(this.appendToBody&&(e.style.transform=c?`translateY(${n-s-i}px)`:`translateY(${n+r-s}px)`,e.style.width=o+"px",e.style.left=l+"px"),c?"top":"buttom");e.getAttribute("direction")!==i&&(e.setAttribute("direction",i),this.#updateDirectionClasses(c,this.appendToBody))}#emitInput(){this.srcElement.dispatchEvent(new CustomEvent("input",{detail:this.value}))}}export default Treeselect;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "treeselectjs",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Treeselect JS",
5
5
  "main": "dist/treeselect-js.js",
6
6
  "repository": {
package/src/list.css CHANGED
@@ -19,6 +19,10 @@
19
19
  height: 30px;
20
20
  }
21
21
 
22
+ .treeselect-list__item:focus {
23
+ outline: none;
24
+ }
25
+
22
26
  .treeselect-list__item--focused {
23
27
  background-color: #f0ffff!important;
24
28
  }
package/src/list.js CHANGED
@@ -67,7 +67,10 @@ const checkInput = ({ id, isGroup, childOf, checked }, flatOptions) => {
67
67
  }
68
68
 
69
69
  const updateValue = (newValue, flatOptions, srcElement) => {
70
- flatOptions.forEach(option => option.checked = false)
70
+ flatOptions.forEach(option => {
71
+ option.checked = false
72
+ option.isPartialChecked = false
73
+ })
71
74
  const toCheck = flatOptions.filter(option => newValue.includes(option.id))
72
75
  toCheck.forEach(option => {
73
76
  option.checked = true
@@ -233,6 +236,26 @@ const getListItemByCheckbox = (checkbox) => {
233
236
  return listItem
234
237
  }
235
238
 
239
+ const validateOptions = (flattedOption) => {
240
+ const { duplications } = flattedOption.reduce((acc, curr) => {
241
+ if (acc.allItems.includes(curr.id)) {
242
+ acc.duplications.push(curr.id)
243
+ }
244
+
245
+ acc.allItems.push(curr.id)
246
+
247
+ return acc
248
+ }, {
249
+ duplications: [],
250
+ allItems: []
251
+ })
252
+
253
+
254
+ if (duplications.length) {
255
+ console.error(`You have duplicated values: ${duplications.join(', ')}! You should use unique values.`)
256
+ }
257
+ }
258
+
236
259
  class TreeselectList {
237
260
  #lastFocusedItem = null
238
261
  #isMouseActionsAvailable = true
@@ -257,6 +280,7 @@ class TreeselectList {
257
280
  this.srcElement = this.#createList()
258
281
 
259
282
  this.updateValue(this.value)
283
+ validateOptions(this.flattedOptions)
260
284
  }
261
285
 
262
286
  // Public methods
@@ -52,7 +52,7 @@
52
52
 
53
53
  .treeselect-list--bottom,
54
54
  .treeselect-list--bottom-to-body {
55
- border-top-color: gainsboro;
55
+ border-top-color: #d7dde4;
56
56
  border-top-left-radius: 0;
57
57
  border-top-right-radius: 0;
58
58
  }
@@ -8,10 +8,7 @@ class Treeselect {
8
8
  #treeselectInput = null
9
9
 
10
10
  // Resize props
11
- #transform = { top: null, bottom: null }
12
- #treeselectInitPosition = null
13
11
  #containerResizer = null
14
- #containerWidth = 0
15
12
 
16
13
  // Outside listeners
17
14
  #scrollEvent = null
@@ -56,12 +53,7 @@ class Treeselect {
56
53
 
57
54
  // Public methods
58
55
  mount () {
59
- if (this.srcElement) {
60
- this.#closeList()
61
- this.srcElement.innerHTML = ''
62
- this.srcElement = null
63
- this.#removeOutsideListeners()
64
- }
56
+ this.destroy()
65
57
 
66
58
  this.srcElement = this.#createTreeselect()
67
59
 
@@ -91,7 +83,7 @@ class Treeselect {
91
83
  this.#closeList()
92
84
  this.srcElement.innerHTML = ''
93
85
  this.srcElement = null
94
- this.#removeOutsideListeners()
86
+ this.#removeOutsideListeners(true)
95
87
  }
96
88
  }
97
89
 
@@ -120,9 +112,7 @@ class Treeselect {
120
112
 
121
113
  if (this.appendToBody) {
122
114
  this.#containerResizer = new ResizeObserver(() => {
123
- const { width } = this.srcElement.getBoundingClientRect()
124
- this.#containerWidth = width
125
- this.updateListPosition(container, list.srcElement, true)
115
+ this.updateListPosition()
126
116
  })
127
117
  }
128
118
 
@@ -137,7 +127,7 @@ class Treeselect {
137
127
  input.srcElement.addEventListener('keydown', (e) => list.callKeyAction(e.key))
138
128
  input.srcElement.addEventListener('search', (e) => {
139
129
  list.updateSearchValue(e.detail)
140
- this.updateListPosition(container, list.srcElement, true)
130
+ this.updateListPosition()
141
131
  })
142
132
  input.srcElement.addEventListener('focus', () => {
143
133
  this.#updateFocusClasses(true)
@@ -166,7 +156,7 @@ class Treeselect {
166
156
  })
167
157
  list.srcElement.addEventListener('arrow-click', () => {
168
158
  input.focus()
169
- this.updateListPosition(container, list.srcElement, true)
159
+ this.updateListPosition()
170
160
  })
171
161
 
172
162
  this.#htmlContainer = container
@@ -188,7 +178,7 @@ class Treeselect {
188
178
  this.#htmlContainer.appendChild(this.#treeselectList.srcElement)
189
179
  }
190
180
 
191
- this.updateListPosition(this.#htmlContainer, this.#treeselectList.srcElement, false)
181
+ this.updateListPosition()
192
182
  this.#updateOpenCloseClasses(true)
193
183
  this.#treeselectList.focusFirstListElement()
194
184
  }
@@ -248,8 +238,10 @@ class Treeselect {
248
238
  }
249
239
  }
250
240
 
251
- #removeOutsideListeners () {
252
- window.removeEventListener('scroll', this.#scrollEvent, true)
241
+ #removeOutsideListeners (isDestroy) {
242
+ if (!this.alwaysOpen || isDestroy) {
243
+ window.removeEventListener('scroll', this.#scrollEvent, true)
244
+ }
253
245
 
254
246
  document.removeEventListener('click', this.#focusEvent, true)
255
247
  document.removeEventListener('focus', this.#focusEvent, true)
@@ -258,7 +250,7 @@ class Treeselect {
258
250
 
259
251
  // Outside Listeners
260
252
  scrollWindowHandler () {
261
- this.updateListPosition(this.#htmlContainer, this.#treeselectList.srcElement, true)
253
+ this.updateListPosition()
262
254
  }
263
255
 
264
256
  focusWindowHandler (e) {
@@ -278,55 +270,35 @@ class Treeselect {
278
270
  }
279
271
 
280
272
  // Update direction of the list. Support appendToBody and standart mode with absolute
281
- updateListPosition (container, list, isNeedForceUpdate) {
282
- const spaceTop = container.getBoundingClientRect().y
283
- const spaceBottom = window.innerHeight - container.getBoundingClientRect().y
284
- const listHeight = list.clientHeight
285
- const spaceDelta = 45
286
- const isTopDirection = spaceTop > spaceBottom && window.innerHeight - spaceTop < listHeight + spaceDelta
287
- const attributeToAdd = isTopDirection ? 'top' : 'buttom'
288
- const currentAttr = list.getAttribute('direction')
289
-
290
- this.#htmlContainer.setAttribute('direction', attributeToAdd)
291
-
292
- // Standart class handler handler with absolute position
293
- if (!this.appendToBody) {
294
- const isNoNeedToUpdate = currentAttr === attributeToAdd
295
-
296
- if (isNoNeedToUpdate) {
297
- return
298
- }
299
-
300
- this.#updateDirectionClasses(isTopDirection, false)
301
-
302
- return
303
- }
304
-
305
- // Append to body handler
306
- if (!this.#treeselectInitPosition || isNeedForceUpdate) {
307
- list.style.transform = null
308
-
309
- const { x: listX, y: listY } = list.getBoundingClientRect()
310
- const { x: containerX, y: containerY } = container.getBoundingClientRect()
311
-
312
- this.#treeselectInitPosition = { containerX, containerY, listX, listY }
273
+ updateListPosition () {
274
+ const list = this.#treeselectList.srcElement
275
+ // We need to reset position
276
+ list.style.transform = null
277
+ const container = this.#htmlContainer
278
+
279
+ const { y: listY, height: listHeight } = list.getBoundingClientRect()
280
+ const { x: containerX, y: containerY, height: containerHeight, width: containerWidth } = container.getBoundingClientRect()
281
+ const windowHeight = window.innerHeight
282
+
283
+ const spaceTop = containerY
284
+ const spaceBottom = windowHeight - containerY - containerHeight
285
+ const isTopDirection = spaceTop > spaceBottom && spaceTop >= listHeight && spaceBottom < listHeight
286
+
287
+ if (this.appendToBody) {
288
+ list.style.transform = isTopDirection
289
+ ? `translateY(${containerY - listY - listHeight}px)`
290
+ : `translateY(${containerY + containerHeight - listY}px)`
291
+ list.style.width = `${containerWidth}px`
292
+ list.style.left = `${containerX}px`
313
293
  }
314
294
 
315
- const { listX, listY, containerX, containerY } = this.#treeselectInitPosition
316
- const containerHeight = container.clientHeight
317
-
318
- // TODO you should use css max-height
319
- // list.style.maxHeight = `${window.innerHeight - containerHeight}px`
295
+ const attributeToAdd = isTopDirection ? 'top' : 'buttom'
296
+ const currentAttr = list.getAttribute('direction')
320
297
 
321
- if (!currentAttr || isNeedForceUpdate) {
322
- this.#transform.top = `translateY(${containerY - listY - listHeight}px)`
323
- this.#transform.bottom = `translateY(${containerY + containerHeight - listY}px)`
298
+ if (currentAttr !== attributeToAdd) {
299
+ list.setAttribute('direction', attributeToAdd)
300
+ this.#updateDirectionClasses(isTopDirection, this.appendToBody)
324
301
  }
325
-
326
- list.style.transform = isTopDirection ? this.#transform.top : this.#transform.bottom
327
- this.#updateDirectionClasses(isTopDirection, true)
328
- list.style.width = `${this.#containerWidth}px`
329
- list.style.left = `${containerX}px`
330
302
  }
331
303
 
332
304
  // Emits