treeselectjs 0.2.0 → 0.2.3

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
@@ -5,7 +5,7 @@ A multi-select js component with nested options.
5
5
  - Full key support (ArrowUp, ArrowDown, Space, ArrowLeft, ArrowRight, Enter)
6
6
  - Screen sensitive direction
7
7
 
8
- ![Example img](treeselectjs.png)
8
+ ![Example img](https://github.com/dipson88/treeselectjs/blob/main/treeselectjs.png?raw=true)
9
9
 
10
10
  ### Getting Started
11
11
  It is a js module.
@@ -119,4 +119,11 @@ 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.
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.
124
+
125
+ ### Notes
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
+ 2) If you want to update props, set props to the entity of the class and then call **mount()** method.
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()**.
package/dist/input.css CHANGED
@@ -1,14 +1,14 @@
1
- .treeselect-input{width:100%;box-sizing:border-box;border:1px solid #d7dde4;border-radius:4px;display:flex;align-items:center;flex-wrap:wrap;padding:2px 4px;padding-right:40px;position:relative;min-height:37px;background-color:#fff;cursor:text}
2
- .treeselect-input--unsearchable{cursor:default}.treeselect-input--unsearchable .treeselect-input__edit{z-index:-1;caret-color:transparent;cursor:default}
3
- .treeselect-input__tags{display:inline-flex;align-items:center;flex-wrap:wrap;gap:4px;max-width:100%;box-sizing:border-box}
4
- .treeselect-input__tags-element{display:inline-flex;align-items:center;background-color:#d7dde4;cursor:pointer;padding:2px 5px;border-radius:2px;font-size:14px;max-width:100%;box-sizing:border-box}
5
- .treeselect-input__tags-element:hover{background-color:#c5c7cb}.treeselect-input__tags-element:hover .treeselect-input__tags-cross svg{stroke:#eb4c42}
6
- .treeselect-input__tags-name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
7
- .treeselect-input__tags-cross{display:flex;margin-left:2px}.treeselect-input__tags-cross svg{width:12px;height:12px}
8
- .treeselect-input__tags-count{font-size:14px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
9
- .treeselect-input__edit{flex:1;min-width:30px;border:0;font-size:14px}.treeselect-input__edit:focus{outline:0}
10
- .treeselect-input__operators{display:flex;max-width:40px;position:absolute;right:2px}
11
- .treeselect-input__clear{display:flex;cursor:pointer}.treeselect-input__clear svg{stroke:#c5c7cb;width:17px;min-width:17px;height:20px}
12
- .treeselect-input__clear:hover svg{stroke:#838790}.treeselect-input__arrow{display:flex;cursor:pointer}
13
- .treeselect-input__arrow svg{stroke:#c5c7cb;width:20px;min-width:20px;height:20px}
1
+ .treeselect-input{width:100%;box-sizing:border-box;border:1px solid #d7dde4;border-radius:4px;display:flex;align-items:center;flex-wrap:wrap;padding:2px 4px;padding-right:40px;position:relative;min-height:37px;background-color:#fff;cursor:text}
2
+ .treeselect-input--unsearchable{cursor:default}.treeselect-input--unsearchable .treeselect-input__edit{z-index:-1;caret-color:transparent;cursor:default}
3
+ .treeselect-input__tags{display:inline-flex;align-items:center;flex-wrap:wrap;gap:4px;max-width:100%;box-sizing:border-box}
4
+ .treeselect-input__tags-element{display:inline-flex;align-items:center;background-color:#d7dde4;cursor:pointer;padding:2px 5px;border-radius:2px;font-size:14px;max-width:100%;box-sizing:border-box}
5
+ .treeselect-input__tags-element:hover{background-color:#c5c7cb}.treeselect-input__tags-element:hover .treeselect-input__tags-cross svg{stroke:#eb4c42}
6
+ .treeselect-input__tags-name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
7
+ .treeselect-input__tags-cross{display:flex;margin-left:2px}.treeselect-input__tags-cross svg{width:12px;height:12px}
8
+ .treeselect-input__tags-count{font-size:14px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
9
+ .treeselect-input__edit{flex:1;min-width:0;border:0;font-size:14px}.treeselect-input__edit:focus{outline:0;min-width:30px}
10
+ .treeselect-input__operators{display:flex;max-width:40px;position:absolute;right:2px}
11
+ .treeselect-input__clear{display:flex;cursor:pointer}.treeselect-input__clear svg{stroke:#c5c7cb;width:17px;min-width:17px;height:20px}
12
+ .treeselect-input__clear:hover svg{stroke:#838790}.treeselect-input__arrow{display:flex;cursor:pointer}
13
+ .treeselect-input__arrow svg{stroke:#c5c7cb;width:20px;min-width:20px;height:20px}
14
14
  .treeselect-input__arrow:hover svg{stroke:#838790}
package/dist/list.js CHANGED
@@ -1 +1 @@
1
- import svg from"./svgIcons.js";const getFlatOptons=(e,i,c=0,l=0)=>e.reduce((e,t)=>{var s=!!t.children?.length;return e.push({id:t.value,name:t.name,childOf:c,isGroup:s,checked:!1,level:l,isClosed:i<=l&&s,hidden:i<l}),s&&(s=getFlatOptons(t.children,i,t.value,l+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 c=i.every(e=>e.checked),l=i.some(e=>e.isPartialChecked||e.checked)&&!c,r=!c&&!l;c&&(s.checked=!0,s.isPartialChecked=!1),l&&(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},c)=>{t&&checkAllChildrenInputs({id:e,checked:i},c),s&&checkAllParentInputs(s,c)},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=(e,c)=>{e.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"),e.childOf||e.isGroup?s.style.paddingLeft=e.isGroup?40*e.level+"px":60*e.level+"px":s.style.paddingLeft="20px",updateCheckboxClasses(e,t)});e=e.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")},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:c}){this.options=e,this.value=t,this.searchText="",this.openLevel=s??0,this.listSlotHtmlComponent=i,this.emptyText=c??"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("click")),"ArrowLeft"===e||"ArrowRight"===e){if(!t)return;const l=t.querySelector(".treeselect-list__item-checkbox"),r=l.getAttribute("input-id");var s=this.flattedOptions.find(e=>e.id===r);const n=t.querySelector(".treeselect-list__item-icon");"ArrowLeft"!==e||s.isClosed||n.dispatchEvent(new Event("click")),"ArrowRight"===e&&s.isClosed&&n.dispatchEvent(new Event("click"))}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 o=getListItemByCheckbox(d[s]);o.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(),c=a.getBoundingClientRect();s&&"ArrowDown"===e?this.srcElement.scroll(0,0):s&&"ArrowUp"===e?this.srcElement.scroll(0,this.srcElement.scrollHeight):i.y+i.height<c.y+c.height?this.srcElement.scroll(0,this.srcElement.scrollTop+c.height):i.y>c.y&&this.srcElement.scroll(0,this.srcElement.scrollTop-c.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("click",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("click",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);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":"0",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("click")),"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 d=t.querySelector(".treeselect-list__item-icon");"ArrowLeft"!==e||s.isClosed||d.dispatchEvent(new Event("click")),"ArrowRight"===e&&s.isClosed&&d.dispatchEvent(new Event("click"))}if("ArrowDown"===e||"ArrowUp"===e){const n=Array.from(this.srcElement.querySelectorAll(".treeselect-list__item-checkbox")).filter(e=>"none"!==window.getComputedStyle(getListItemByCheckbox(e)).display);if(n.length)if(t){s=n.findIndex(e=>getListItemByCheckbox(e).classList.contains("treeselect-list__item--focused"));const o=getListItemByCheckbox(n[s]);o.classList.remove("treeselect-list__item--focused");var s="ArrowDown"===e?s+1:s-1,i="ArrowDown"===e?0:n.length-1,i=n[s]??n[i],s=!n[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(n[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("click",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("click",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,8 +1,8 @@
1
- @import './input.css';@import './list.css';.treeselect{width:100%;position:relative;box-sizing:border-box}
2
- .treeselect--disabled{pointer-events:none}.treeselect-list{position:absolute;left:0;border-radius:4px;box-sizing:border-box}
3
- .treeselect .treeselect-list{position:absolute}.treeselect-input--focused{border-color:#101010}
4
- .treeselect-input--opened.treeselect-input--top{border-top-color:transparent;border-top-left-radius:0;border-top-right-radius:0}
5
- .treeselect-input--opened.treeselect-input--bottom{border-bottom-color:transparent;border-bottom-left-radius:0;border-bottom-right-radius:0}
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}
1
+ @import './input.css';@import './list.css';.treeselect{width:100%;position:relative;box-sizing:border-box}
2
+ .treeselect--disabled{pointer-events:none}.treeselect-list{position:absolute;left:0;border-radius:4px;box-sizing:border-box}
3
+ .treeselect .treeselect-list{position:absolute}.treeselect-input--focused{border-color:#101010}
4
+ .treeselect-input--opened.treeselect-input--top{border-top-color:transparent;border-top-left-radius:0;border-top-right-radius:0}
5
+ .treeselect-input--opened.treeselect-input--bottom{border-bottom-color:transparent;border-bottom-left-radius:0;border-bottom-right-radius:0}
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}
8
8
  .treeselect-list--top{left:0;bottom:100%}.treeselect-list--bottom{left:0;top:100%}
package/package.json CHANGED
@@ -1,11 +1,8 @@
1
1
  {
2
2
  "name": "treeselectjs",
3
- "version": "0.2.0",
3
+ "version": "0.2.3",
4
4
  "description": "Treeselect JS",
5
5
  "main": "dist/treeselect-js.js",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
8
- },
9
6
  "repository": {
10
7
  "type": "git",
11
8
  "url": "git+https://github.com/dipson88/treeselectjs.git"
@@ -16,7 +13,7 @@
16
13
  "js"
17
14
  ],
18
15
  "author": "Dzmitry Zhuraukou",
19
- "license": "ISC",
16
+ "license": "MIT",
20
17
  "bugs": {
21
18
  "url": "https://github.com/dipson88/treeselectjs/issues"
22
19
  },
package/src/input.css CHANGED
@@ -78,13 +78,14 @@
78
78
 
79
79
  .treeselect-input__edit {
80
80
  flex: 1;
81
- min-width: 30px;
81
+ min-width: 0;
82
82
  border: none;
83
83
  font-size: 14px;
84
84
  }
85
85
 
86
86
  .treeselect-input__edit:focus {
87
87
  outline: none;
88
+ min-width: 30px;
88
89
  }
89
90
 
90
91
  .treeselect-input__operators {
package/src/list.js CHANGED
@@ -125,12 +125,7 @@ const updateDOM = (flatOptions, srcElement) => {
125
125
  listItem.classList.remove('treeselect-list__item--hidden')
126
126
  }
127
127
 
128
- if (!option.childOf && !option.isGroup) {
129
- listItem.style.paddingLeft = `${20}px`
130
- } else {
131
- listItem.style.paddingLeft = option.isGroup ? `${option.level * 40}px` : `${option.level * 60}px`
132
- }
133
-
128
+ updateLeftPaddingItems(option, listItem, flatOptions)
134
129
  updateCheckboxClasses(option, input)
135
130
  })
136
131
 
@@ -144,6 +139,26 @@ const updateDOM = (flatOptions, srcElement) => {
144
139
  }
145
140
  }
146
141
 
142
+ const updateLeftPaddingItems = (option, listItem, flatOptions) => {
143
+ const isZeroLevel = option.level === 0
144
+ const defaultPadding = 20
145
+ const zeroLevelItemPadding = 5
146
+
147
+ if (isZeroLevel) {
148
+ const isGroupsExistOnLevel = flatOptions.some(item => item.isGroup && item.level === option.level)
149
+ const itemPadding = !option.isGroup && isGroupsExistOnLevel ? `${defaultPadding}px` : `${zeroLevelItemPadding}px`
150
+ listItem.style.paddingLeft = option.isGroup ? '0' : itemPadding
151
+ } else {
152
+ listItem.style.paddingLeft = option.isGroup
153
+ ? `${option.level * defaultPadding}px`
154
+ : `${(option.level * defaultPadding) + defaultPadding}px`
155
+ }
156
+
157
+ // You can use css selectors to reset params with !important
158
+ listItem.setAttribute('level', option.level)
159
+ listItem.setAttribute('group', option.isGroup)
160
+ }
161
+
147
162
  // Updates classes
148
163
  const updateCheckboxClasses = (option, input) => {
149
164
  const inputContainer = input.parentNode
@@ -16,6 +16,7 @@
16
16
  left: 0;
17
17
  border-radius: 4px;
18
18
  box-sizing: border-box;
19
+ z-index: 1010;
19
20
  }
20
21
 
21
22
  .treeselect .treeselect-list {
@@ -13,6 +13,11 @@ class Treeselect {
13
13
  #containerResizer = null
14
14
  #containerWidth = 0
15
15
 
16
+ // Outside listeners
17
+ #scrollEvent = null
18
+ #focusEvent = null
19
+ #blurEvent = null
20
+
16
21
  constructor ({
17
22
  parentHtmlContainer,
18
23
  value,
@@ -42,15 +47,10 @@ class Treeselect {
42
47
  this.grouped = grouped ?? true
43
48
  this.listSlotHtmlComponent = listSlotHtmlComponent ?? null
44
49
  this.disabled = disabled ?? false
45
- this.emptyText = emptyText
50
+ this.emptyText = emptyText ?? 'No results found...'
46
51
 
47
52
  this.srcElement = null
48
53
 
49
- // Outside listeners
50
- this.scrollEvent = null
51
- this.focusEvent = null
52
- this.blurEvent = null
53
-
54
54
  this.mount()
55
55
  }
56
56
 
@@ -65,9 +65,9 @@ class Treeselect {
65
65
 
66
66
  this.srcElement = this.#createTreeselect()
67
67
 
68
- this.scrollEvent = this.scrollWindowHandler.bind(this)
69
- this.focusEvent = this.focusWindowHandler.bind(this)
70
- this.blurEvent = this.blurWindowHandler.bind(this)
68
+ this.#scrollEvent = this.scrollWindowHandler.bind(this)
69
+ this.#focusEvent = this.focusWindowHandler.bind(this)
70
+ this.#blurEvent = this.blurWindowHandler.bind(this)
71
71
 
72
72
  if (this.alwaysOpen) {
73
73
  this.#treeselectInput.openClose()
@@ -86,6 +86,15 @@ class Treeselect {
86
86
  this.#treeselectInput.updateValue(inputNewValue)
87
87
  }
88
88
 
89
+ destroy () {
90
+ if (this.srcElement) {
91
+ this.#closeList()
92
+ this.srcElement.innerHTML = ''
93
+ this.srcElement = null
94
+ this.#removeOutsideListeners()
95
+ }
96
+ }
97
+
89
98
  #createTreeselect () {
90
99
  const container = this.parentHtmlContainer
91
100
  container.classList.add('treeselect')
@@ -132,9 +141,9 @@ class Treeselect {
132
141
  })
133
142
  input.srcElement.addEventListener('focus', () => {
134
143
  this.#updateFocusClasses(true)
135
- document.addEventListener('mousedown', this.focusEvent, true)
136
- document.addEventListener('focus', this.focusEvent, true)
137
- window.addEventListener('blur', this.blurEvent)
144
+ document.addEventListener('mousedown', this.#focusEvent, true)
145
+ document.addEventListener('focus', this.#focusEvent, true)
146
+ window.addEventListener('blur', this.#blurEvent)
138
147
  }, true)
139
148
 
140
149
  if (!this.alwaysOpen) {
@@ -167,7 +176,7 @@ class Treeselect {
167
176
  }
168
177
 
169
178
  #openList () {
170
- window.addEventListener('scroll', this.scrollEvent, true)
179
+ window.addEventListener('scroll', this.#scrollEvent, true)
171
180
 
172
181
  if (this.appendToBody) {
173
182
  document.body.appendChild(this.#treeselectList.srcElement)
@@ -182,7 +191,14 @@ class Treeselect {
182
191
  }
183
192
 
184
193
  #closeList () {
185
- window.removeEventListener('scroll', this.scrollEvent, true)
194
+ window.removeEventListener('scroll', this.#scrollEvent, true)
195
+ const isElementExist = this.appendToBody
196
+ ? document.body.contains(this.#treeselectList.srcElement)
197
+ : this.#htmlContainer.contains(this.#treeselectList.srcElement)
198
+
199
+ if (!isElementExist) {
200
+ return
201
+ }
186
202
 
187
203
  if (this.appendToBody) {
188
204
  document.body.removeChild(this.#treeselectList.srcElement)
@@ -230,16 +246,16 @@ class Treeselect {
230
246
  }
231
247
 
232
248
  #removeOutsideListeners () {
233
- window.removeEventListener('scroll', this.scrollEvent, true)
249
+ window.removeEventListener('scroll', this.#scrollEvent, true)
234
250
 
235
- document.removeEventListener('click', this.focusEvent, true)
236
- document.removeEventListener('focus', this.focusEvent, true)
237
- window.removeEventListener('blur', this.blurEvent)
251
+ document.removeEventListener('click', this.#focusEvent, true)
252
+ document.removeEventListener('focus', this.#focusEvent, true)
253
+ window.removeEventListener('blur', this.#blurEvent)
238
254
  }
239
255
 
240
256
  // Outside Listeners
241
257
  scrollWindowHandler () {
242
- this.updateListPosition(this.#htmlContainer, this.#treeselectList.srcElement, false)
258
+ this.updateListPosition(this.#htmlContainer, this.#treeselectList.srcElement, true)
243
259
  }
244
260
 
245
261
  focusWindowHandler (e) {