treeselectjs 0.2.8 → 0.2.9

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
@@ -98,33 +98,36 @@ slot.addEventListener('click', (e) => {
98
98
  ### Props
99
99
  Name | Type (default) | Description
100
100
  ------------- | ------------- | -------------
101
- parentHtmlContainer | HTMLElement (required!) | It should be a HTML element (div), it will be changed to the list container.
102
- value | Array[String] ([]) | It is an array with ids.
103
- 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.
104
- openLevel | Number (0) | All groups will be opened to this level.
105
- appendToBody | Boolean (false) | List will be appended to the body instead of the input container.
106
- alwaysOpen | Boolean (false) | List will be always opened. You can use it for comfortable style changing. If you what to use it as an opened list, turn `staticList' to `true`.
107
- showTags | Boolean (true) | Selected values look like tags. The false value shows results as '{count} elements selected'.
108
- clearable | Boolean (true) | Clear icon is available.
109
- searchable | Boolean (true) | Search is available.
110
- placeholder | String ('Search...') | Placeholder text.
111
- grouped | Boolean (true) | Show groups in the input and group leafs if all group selected.
112
- listSlotHtmlComponent | HTMLElement (null) | It should be a HTML element, it will be append to the end of the list.
113
- disabled | Boolean (false) | List will be disabled.
114
- emptyText | String ('No results found...') | A empty list text.
115
- staticList | Boolean (false) | Add the list as a static DOM element. List doesn't overlap content. This prop will be ignored if you use `appendToBody`.
101
+ **parentHtmlContainer** | HTMLElement (required!) | It should be a HTML element (div), it will be changed to the list container.
102
+ **value** | Array[String] ([]) | An array of `value` from `options` prop. This value will be selected on load of the treeselect. You can call `updateValue` to update prop or set value `treeselect.value` and call `mount`. The `value` changes if you check/uncheck checkboxes or remove tags from the input.
103
+ **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.
104
+ **openLevel** | Number (0) | All groups will be opened to this level.
105
+ **appendToBody** | Boolean (false) | List will be appended to the body instead of the input container.
106
+ **alwaysOpen** | Boolean (false) | List will be always opened. You can use it for comfortable style changing. If you what to use it as an opened list, turn `staticList` to `true`.
107
+ **showTags** | Boolean (true) | Selected values look like tags. The false value shows results as '{count} elements selected'. You can change text if you use `tagsCountText` prop. For one selected element, you will see a name of this element.
108
+ **tagsCountText** | String ('elements selected') | This text will be shown if you use 'showTags'. This text will be inserted after the count of the selected elements - ```'{count} {tagsCountText}'```.
109
+ **clearable** | Boolean (true) | Clear icon is available.
110
+ **searchable** | Boolean (true) | Search is available.
111
+ **placeholder** | String ('Search...') | Placeholder text.
112
+ **grouped** | Boolean (true) | Show groups in the input and group leafs if all group selected.
113
+ **listSlotHtmlComponent** | HTMLElement (null) | It should be a HTML element, it will be append to the end of the list.
114
+ **disabled** | Boolean (false) | List will be disabled.
115
+ **emptyText** | String ('No results found...') | A empty list text.
116
+ **staticList** | Boolean (false) | Add the list as a static DOM element. List doesn't overlap content. This prop will be ignored if you use `appendToBody`.
116
117
 
117
118
  ### Emits
118
119
  Name | Return Type | Description
119
120
  ------------- | ------------- | -------------
120
- input | Array[String] | Returns selected ids without groups, only leafs.
121
+ **input** | Array[String] | Returns selected ids without groups, only leafs.
121
122
 
122
123
  ### Methods
123
124
  Name | Params | Description
124
125
  ------------- | ------------- | -------------
125
- updateValue | Array[String] | Update selected values.
126
- mount | None | Helps to remount and update settings. Change settings that you need (treeselect.appendToBody = true), then call mount().
127
- 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)**.
126
+ **updateValue** | Array[String] | Update selected values.
127
+ **mount** | None | Helps to remount and update settings. Change settings that you need (treeselect.appendToBody = true), then call mount().
128
+ **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)```.
129
+ **focus** | None | Focuses treeselect input without open/close state changes.
130
+ **toggleOpenClose** | None | Open or close treeselect list and focus treeselect input.
128
131
 
129
132
  ### Notes
130
133
  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**.
package/dist/input.js CHANGED
@@ -1 +1 @@
1
- import svg from"./svgIcons.js";class TreeselectInput{#htmlTagsSection=null;#htmlEditControl=null;#htmlOperators=null;#htmlArrow=null;#openEvent=new CustomEvent("open");#closeEvent=new CustomEvent("close");constructor({value:e,showTags:t,clearable:s,isAlwaysOpened:a,searchable:i,placeholder:n,disabled:r}){this.value=e,this.showTags=t??!0,this.searchable=i??!0,this.placeholder=n??"Search...",this.clearable=s??!0,this.isAlwaysOpened=a??!1,this.disabled=r??!1,this.isOpened=!1,this.searchText="",this.srcElement=this.#createTreeselectInput(),this.#updateDOM()}focus(){this.#htmlEditControl.focus()}blur(){this.isOpened&&this.#updateOpenClose()}updateValue(e){this.value=e,this.#updateTags(),this.#updateEditControl()}removeItem(t){this.value=this.value.filter(e=>e.id!==t),this.#emitInput(),this.#updateTags(),this.#updateEditControl()}clear(){this.value=[],this.searchText="",this.#emitSearch(""),this.#emitInput(),this.#updateTags(),this.#updateEditControl()}openClose(){this.#updateOpenClose()}#updateDOM(){this.#updateTags(),this.#updateEditControl(),this.#updateOperators()}#updateTags(){this.#htmlTagsSection.innerHTML="",this.showTags?this.#htmlTagsSection.append(...this.#createTags()):this.#htmlTagsSection.appendChild(this.#createCountElement())}#updateOperators(){const e=[];this.#htmlOperators.innerHTML="",this.clearable&&e.push(this.#createClearButton()),this.isAlwaysOpened||e.push(this.#createInputArrow(this.isOpened)),e.length&&this.#htmlOperators.append(...e)}#updateArrowDirection(){var e;this.isAlwaysOpened||(e=this.isOpened?svg.arrowUp:svg.arrowDown,this.#htmlArrow.innerHTML=e)}#updateEditControl(){this.value?.length?this.#htmlEditControl.removeAttribute("placeholder"):this.#htmlEditControl.setAttribute("placeholder",this.placeholder),this.searchable?this.srcElement.classList.remove("treeselect-input--unsearchable"):this.srcElement.classList.add("treeselect-input--unsearchable"),this.#htmlEditControl.value=this.searchText}#updateOpenClose(){this.isOpened=!this.isOpened,this.#updateArrowDirection(),this.isOpened?this.#emitOpen():this.#emitClose()}#createTreeselectInput(){const e=document.createElement("div");return e.classList.add("treeselect-input"),e.setAttribute("tabindex","-1"),this.#htmlTagsSection=this.#createTagsSection(),this.#htmlEditControl=this.#createControl(),this.#htmlOperators=this.#createOperators(),e.addEventListener("mousedown",e=>{e.preventDefault(),this.isOpened||this.#updateOpenClose(),this.focus()}),e.append(this.#htmlTagsSection,this.#htmlEditControl,this.#htmlOperators),e}#createTagsSection(){const e=document.createElement("div");return e.classList.add("treeselect-input__tags"),e}#createTags(){return this.value.map(t=>{const e=document.createElement("div");e.classList.add("treeselect-input__tags-element"),e.setAttribute("tabindex","-1"),e.setAttribute("tag-id",t.id),e.setAttribute("title",t.name);var s=this.#createTagName(t.name),a=this.#createTagCross();return e.addEventListener("mousedown",e=>{e.preventDefault(),e.stopPropagation(),this.focus(),this.removeItem(t.id)}),e.append(s,a),e})}#createTagName(e){const t=document.createElement("span");return t.classList.add("treeselect-input__tags-name"),t.innerHTML=e,t}#createTagCross(){const e=document.createElement("span");return e.classList.add("treeselect-input__tags-cross"),e.innerHTML=svg.cross,e}#createCountElement(){const e=document.createElement("span");return e.classList.add("treeselect-input__tags-count"),this.value.length?e.innerHTML=1===this.value.length?this.value[0].name:this.value.length+" elements selected":e.innerHTML="",e}#createControl(){const a=document.createElement("input");return a.classList.add("treeselect-input__edit"),this.disabled&&a.setAttribute("tabindex","-1"),a.addEventListener("keydown",e=>{"Backspace"!==e.key||this.searchText.length||!this.value.length||this.showTags||this.clear(),"Backspace"===e.key&&!this.searchText.length&&this.value.length&&this.removeItem(this.value[this.value.length-1].id),"Space"!==e.code||this.searchText&&this.searchable||this.#updateOpenClose()}),a.addEventListener("input",e=>{e.stopPropagation();var t=this.searchText,s=a.value.trim();0===t.length&&0===s.length?a.value="":(this.searchable?(this.#emitSearch(e.target.value),this.isOpened||this.#updateOpenClose()):a.value="",this.searchText=a.value)}),a}#createOperators(){const e=document.createElement("div");return e.classList.add("treeselect-input__operators"),e}#createClearButton(){const e=document.createElement("span");return e.classList.add("treeselect-input__clear"),e.setAttribute("tabindex","-1"),e.innerHTML=svg.clear,e.addEventListener("mousedown",e=>{e.preventDefault(),e.stopPropagation(),this.#htmlEditControl.focus(),(this.searchText.length||this.value.length)&&this.clear()}),e}#createInputArrow(e){return this.#htmlArrow=document.createElement("span"),this.#htmlArrow.classList.add("treeselect-input__arrow"),this.#htmlArrow.innerHTML=e?svg.arrowUp:svg.arrowDown,this.#htmlArrow.addEventListener("mousedown",e=>{e.stopPropagation(),e.preventDefault(),this.focus(),this.#updateOpenClose()}),this.#htmlArrow}#emitInput(){this.srcElement.dispatchEvent(new CustomEvent("input",{detail:this.value}))}#emitSearch(e){this.srcElement.dispatchEvent(new CustomEvent("search",{detail:e}))}#emitOpen(){this.srcElement.dispatchEvent(this.#openEvent)}#emitClose(){this.srcElement.dispatchEvent(this.#closeEvent)}}export default TreeselectInput;
1
+ import svg from"./svgIcons.js";class TreeselectInput{#htmlTagsSection=null;#htmlEditControl=null;#htmlOperators=null;#htmlArrow=null;#openEvent=new CustomEvent("open");#closeEvent=new CustomEvent("close");constructor({value:t,showTags:e,tagsCountText:s,clearable:a,isAlwaysOpened:i,searchable:n,placeholder:r,disabled:h}){this.value=t,this.showTags=e??!0,this.tagsCountText=s??"elements selected",this.searchable=n??!0,this.placeholder=r??"Search...",this.clearable=a??!0,this.isAlwaysOpened=i??!1,this.disabled=h??!1,this.isOpened=!1,this.searchText="",this.srcElement=this.#createTreeselectInput(),this.#updateDOM()}focus(){this.#htmlEditControl.focus()}blur(){this.isOpened&&this.#updateOpenClose()}updateValue(t){this.value=t,this.#updateTags(),this.#updateEditControl()}removeItem(e){this.value=this.value.filter(t=>t.id!==e),this.#emitInput(),this.#updateTags(),this.#updateEditControl()}clear(){this.value=[],this.searchText="",this.#emitSearch(""),this.#emitInput(),this.#updateTags(),this.#updateEditControl()}openClose(){this.#updateOpenClose()}#updateDOM(){this.#updateTags(),this.#updateEditControl(),this.#updateOperators()}#updateTags(){this.#htmlTagsSection.innerHTML="",this.showTags?this.#htmlTagsSection.append(...this.#createTags()):this.#htmlTagsSection.appendChild(this.#createCountElement())}#updateOperators(){const t=[];this.#htmlOperators.innerHTML="",this.clearable&&t.push(this.#createClearButton()),this.isAlwaysOpened||t.push(this.#createInputArrow(this.isOpened)),t.length&&this.#htmlOperators.append(...t)}#updateArrowDirection(){var t;this.isAlwaysOpened||(t=this.isOpened?svg.arrowUp:svg.arrowDown,this.#htmlArrow.innerHTML=t)}#updateEditControl(){this.value?.length?this.#htmlEditControl.removeAttribute("placeholder"):this.#htmlEditControl.setAttribute("placeholder",this.placeholder),this.searchable?this.srcElement.classList.remove("treeselect-input--unsearchable"):this.srcElement.classList.add("treeselect-input--unsearchable"),this.#htmlEditControl.value=this.searchText}#updateOpenClose(){this.isOpened=!this.isOpened,this.#updateArrowDirection(),this.isOpened?this.#emitOpen():this.#emitClose()}#createTreeselectInput(){const t=document.createElement("div");return t.classList.add("treeselect-input"),t.setAttribute("tabindex","-1"),this.#htmlTagsSection=this.#createTagsSection(),this.#htmlEditControl=this.#createControl(),this.#htmlOperators=this.#createOperators(),t.addEventListener("mousedown",t=>{t.preventDefault(),this.isOpened||this.#updateOpenClose(),this.focus()}),t.append(this.#htmlTagsSection,this.#htmlEditControl,this.#htmlOperators),t}#createTagsSection(){const t=document.createElement("div");return t.classList.add("treeselect-input__tags"),t}#createTags(){return this.value.map(e=>{const t=document.createElement("div");t.classList.add("treeselect-input__tags-element"),t.setAttribute("tabindex","-1"),t.setAttribute("tag-id",e.id),t.setAttribute("title",e.name);var s=this.#createTagName(e.name),a=this.#createTagCross();return t.addEventListener("mousedown",t=>{t.preventDefault(),t.stopPropagation(),this.focus(),this.removeItem(e.id)}),t.append(s,a),t})}#createTagName(t){const e=document.createElement("span");return e.classList.add("treeselect-input__tags-name"),e.innerHTML=t,e}#createTagCross(){const t=document.createElement("span");return t.classList.add("treeselect-input__tags-cross"),t.innerHTML=svg.cross,t}#createCountElement(){const t=document.createElement("span");return t.classList.add("treeselect-input__tags-count"),this.value.length?t.innerHTML=1===this.value.length?this.value[0].name:this.value.length+" "+this.tagsCountText:t.innerHTML="",t}#createControl(){const a=document.createElement("input");return a.classList.add("treeselect-input__edit"),this.disabled&&a.setAttribute("tabindex","-1"),a.addEventListener("keydown",t=>{"Backspace"!==t.key||this.searchText.length||!this.value.length||this.showTags||this.clear(),"Backspace"===t.key&&!this.searchText.length&&this.value.length&&this.removeItem(this.value[this.value.length-1].id),"Space"!==t.code||this.searchText&&this.searchable||this.#updateOpenClose()}),a.addEventListener("input",t=>{t.stopPropagation();var e=this.searchText,s=a.value.trim();0===e.length&&0===s.length?a.value="":(this.searchable?(this.#emitSearch(t.target.value),this.isOpened||this.#updateOpenClose()):a.value="",this.searchText=a.value)}),a}#createOperators(){const t=document.createElement("div");return t.classList.add("treeselect-input__operators"),t}#createClearButton(){const t=document.createElement("span");return t.classList.add("treeselect-input__clear"),t.setAttribute("tabindex","-1"),t.innerHTML=svg.clear,t.addEventListener("mousedown",t=>{t.preventDefault(),t.stopPropagation(),this.#htmlEditControl.focus(),(this.searchText.length||this.value.length)&&this.clear()}),t}#createInputArrow(t){return this.#htmlArrow=document.createElement("span"),this.#htmlArrow.classList.add("treeselect-input__arrow"),this.#htmlArrow.innerHTML=t?svg.arrowUp:svg.arrowDown,this.#htmlArrow.addEventListener("mousedown",t=>{t.stopPropagation(),t.preventDefault(),this.focus(),this.#updateOpenClose()}),this.#htmlArrow}#emitInput(){this.srcElement.dispatchEvent(new CustomEvent("input",{detail:this.value}))}#emitSearch(t){this.srcElement.dispatchEvent(new CustomEvent("search",{detail:t}))}#emitOpen(){this.srcElement.dispatchEvent(this.#openEvent)}#emitClose(){this.srcElement.dispatchEvent(this.#closeEvent)}}export default TreeselectInput;
package/dist/list.js CHANGED
@@ -1 +1 @@
1
- import svg from"./svgIcons.js";const getFlatOptions=(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=getFlatOptions(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.isPartialChecked=!1,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),[]),getAllFlattenParents=(s,i)=>i.reduce((e,t)=>(t.id===s&&(e.push(t),t.childOf&&e.push(...getAllFlattenParents(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(`Validation: 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=getFlatOptions(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){if(i!==this.searchText){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=getAllFlattenParents(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.#emitArrowClick()}#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)}}#emitArrowClick(){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 getFlatOptions=(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=getFlatOptions(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.isPartialChecked=!1,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),[]),getAllFlattenParents=(s,i)=>i.reduce((e,t)=>(t.id===s&&(e.push(t),t.childOf&&e.push(...getAllFlattenParents(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(`Validation: 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=getFlatOptions(this.options,this.openLevel),this.flattedOptionsBeforeSearch=this.flattedOptions,this.selectedNodes={nodes:[],groupedNodes:[]},this.srcElement=this.#createList(),this.updateValue(this.value),validateOptions(this.flattedOptions)}updateValue(e){updateValue(e,this.flattedOptions,this.srcElement),this.#updateSelectedNodes()}updateSearchValue(i){if(i!==this.searchText){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=getAllFlattenParents(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 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 d=getListItemByCheckbox(n[s]);d.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("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.#emitArrowClick()}#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={nodes:getCheckedValues(this.flattedOptions),groupedNodes:getGroupedValues(this.flattedOptions)}}#emitArrowClick(){this.srcElement.dispatchEvent(new CustomEvent("arrow-click"))}#emitInput(){this.#updateSelectedNodes(),this.srcElement.dispatchEvent(new CustomEvent("input",{detail:this.selectedNodes}))}}export default TreeselectList;
@@ -1 +1 @@
1
- import TreeselectInput from"./input.js";import TreeselectList from"./list.js";const validateProps=({parentHtmlContainer:e,staticList:t,appendToBody:s})=>{e||console.error("Validation: parentHtmlContainer prop is required!"),t&&s&&console.error("Validation: You should set staticList to false if you use appendToBody!")};class Treeselect{#htmlContainer=null;#treeselectList=null;#treeselectInput=null;#containerResizer=null;#scrollEvent=null;#resizeEvent=null;#focusEvent=null;#blurEvent=null;#isListOpened=!1;constructor({parentHtmlContainer:e,value:t,options:s,openLevel:i,appendToBody:n,alwaysOpen:l,showTags:r,clearable:o,searchable:a,placeholder:c,grouped:d,listSlotHtmlComponent:h,disabled:p,emptyText:u,staticList:m}){validateProps({parentHtmlContainer:e,staticList:m,appendToBody:n}),this.parentHtmlContainer=e,this.value=t??[],this.options=s??[],this.openLevel=i??0,this.appendToBody=n??!0,this.alwaysOpen=l&&!p,this.showTags=r??!0,this.clearable=o??!0,this.searchable=a??!0,this.placeholder=c??"Search...",this.grouped=d??!0,this.listSlotHtmlComponent=h??null,this.disabled=p??!1,this.emptyText=u??"No results found...",this.staticList=m&&!this.appendToBody,this.srcElement=null,this.mount()}mount(){this.destroy(),this.srcElement=this.#createTreeselect(),this.#scrollEvent=this.scrollWindowHandler.bind(this),this.#resizeEvent=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 n=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()})),n.srcElement.addEventListener("input",e=>{e=e.detail.map(({id:e})=>e);this.value=e,t.updateValue(e),this.#emitInput()}),n.srcElement.addEventListener("open",()=>this.#openList()),n.srcElement.addEventListener("keydown",e=>{this.#isListOpened&&t.callKeyAction(e.key)}),n.srcElement.addEventListener("search",e=>{t.updateSearchValue(e.detail),this.updateListPosition()}),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()}),t.srcElement.addEventListener("mouseup",()=>{n.focus()},!0),t.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()}),t.srcElement.addEventListener("arrow-click",()=>{n.focus(),this.updateListPosition()}),this.#htmlContainer=e,this.#treeselectList=t,this.#treeselectInput=n,e.append(n.srcElement),e}#openList(){this.#isListOpened=!0,window.addEventListener("scroll",this.#scrollEvent,!0),window.addEventListener("resize",this.#resizeEvent),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(){this.#isListOpened=!1,window.removeEventListener("scroll",this.#scrollEvent,!0),window.removeEventListener("resize",this.#resizeEvent),(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"),this.staticList?this.#treeselectList.srcElement.classList.add("treeselect-list--static"):this.#treeselectList.srcElement.classList.remove("treeselect-list--static")}#removeOutsideListeners(e){this.alwaysOpen&&!e||(window.removeEventListener("scroll",this.#scrollEvent,!0),window.removeEventListener("resize",this.#resizeEvent)),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:n,y:l,height:r,width:o}=t.getBoundingClientRect(),a=window.innerHeight-l-r,a=a<l&&i<=l&&a<i,i=(this.appendToBody&&(e.style.transform=a?`translateY(${l-s-i}px)`:`translateY(${l+r-s}px)`,e.style.width=o+"px",e.style.left=n+window.scrollX+"px"),a?"top":"bottom");e.getAttribute("direction")!==i&&(e.setAttribute("direction",i),this.#updateDirectionClasses(a,this.appendToBody))}#emitInput(){this.srcElement.dispatchEvent(new CustomEvent("input",{detail:this.value}))}}export default Treeselect;
1
+ import TreeselectInput from"./input.js";import TreeselectList from"./list.js";const validateProps=({parentHtmlContainer:e,staticList:t,appendToBody:s})=>{e||console.error("Validation: parentHtmlContainer prop is required!"),t&&s&&console.error("Validation: You should set staticList to false if you use appendToBody!")},getOnlyIds=e=>e.map(e=>e.id);class Treeselect{#htmlContainer=null;#treeselectList=null;#treeselectInput=null;#containerResizer=null;#scrollEvent=null;#resizeEvent=null;#focusEvent=null;#blurEvent=null;constructor({parentHtmlContainer:e,value:t,options:s,openLevel:i,appendToBody:n,alwaysOpen:l,showTags:r,tagsCountText:o,clearable:c,searchable:a,placeholder:d,grouped:h,listSlotHtmlComponent:p,disabled:u,emptyText:m,staticList:L}){validateProps({parentHtmlContainer:e,staticList:L,appendToBody:n}),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.tagsCountText=o??"elements selected",this.clearable=c??!0,this.searchable=a??!0,this.placeholder=d??"Search...",this.grouped=h??!0,this.listSlotHtmlComponent=p??null,this.disabled=u??!1,this.emptyText=m??"No results found...",this.staticList=L&&!this.appendToBody,this.isListOpened=!1,this.srcElement=null,this.mount()}mount(){this.destroy(),this.srcElement=this.#createTreeselect(),this.#scrollEvent=this.scrollWindowHandler.bind(this),this.#resizeEvent=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{groupedNodes:e,nodes: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))}focus(){this.#treeselectInput&&this.#treeselectInput.focus()}toggleOpenClose(){this.#treeselectInput&&(this.#treeselectInput.openClose(),this.#treeselectInput.focus())}#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{groupedNodes:s,nodes:i}=t.selectedNodes;const n=new TreeselectInput({value:this.grouped?s:i,showTags:this.showTags,tagsCountText:this.tagsCountText,clearable:this.clearable,isAlwaysOpened:this.alwaysOpen,searchable:this.searchable,placeholder:this.placeholder,disabled:this.disabled});return this.appendToBody&&(this.#containerResizer=new ResizeObserver(()=>{this.updateListPosition()})),n.srcElement.addEventListener("input",e=>{e=getOnlyIds(e.detail),t.updateValue(e),e=t.selectedNodes.nodes;this.value=getOnlyIds(e),this.#emitInput()}),n.srcElement.addEventListener("open",()=>this.#openList()),n.srcElement.addEventListener("keydown",e=>{this.isListOpened&&t.callKeyAction(e.key)}),n.srcElement.addEventListener("search",e=>{t.updateSearchValue(e.detail),this.updateListPosition()}),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()}),t.srcElement.addEventListener("mouseup",()=>{n.focus()},!0),t.srcElement.addEventListener("input",e=>{var{groupedNodes:e,nodes:t}=e.detail,e=this.grouped?e:t;n.updateValue(e),this.value=getOnlyIds(t),n.focus(),this.#emitInput()}),t.srcElement.addEventListener("arrow-click",()=>{n.focus(),this.updateListPosition()}),this.#htmlContainer=e,this.#treeselectList=t,this.#treeselectInput=n,e.append(n.srcElement),e}#openList(){this.isListOpened=!0,window.addEventListener("scroll",this.#scrollEvent,!0),window.addEventListener("resize",this.#resizeEvent),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(){this.isListOpened=!1,window.removeEventListener("scroll",this.#scrollEvent,!0),window.removeEventListener("resize",this.#resizeEvent),(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"),this.staticList?this.#treeselectList.srcElement.classList.add("treeselect-list--static"):this.#treeselectList.srcElement.classList.remove("treeselect-list--static")}#removeOutsideListeners(e){this.alwaysOpen&&!e||(window.removeEventListener("scroll",this.#scrollEvent,!0),window.removeEventListener("resize",this.#resizeEvent)),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:n,y:l,height:r,width:o}=t.getBoundingClientRect(),c=window.innerHeight-l-r,c=c<l&&i<=l&&c<i,i=(this.appendToBody&&(e.style.transform=c?`translateY(${l-s-i}px)`:`translateY(${l+r-s}px)`,e.style.width=o+"px",e.style.left=n+window.scrollX+"px"),c?"top":"bottom");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.8",
3
+ "version": "0.2.9",
4
4
  "description": "Treeselect JS",
5
5
  "main": "dist/treeselect-js.js",
6
6
  "repository": {
package/src/input.js CHANGED
@@ -11,6 +11,7 @@ class TreeselectInput {
11
11
  constructor ({
12
12
  value,
13
13
  showTags,
14
+ tagsCountText,
14
15
  clearable,
15
16
  isAlwaysOpened,
16
17
  searchable,
@@ -20,6 +21,7 @@ class TreeselectInput {
20
21
  this.value = value
21
22
 
22
23
  this.showTags = showTags ?? true
24
+ this.tagsCountText = tagsCountText ?? 'elements selected'
23
25
  this.searchable = searchable ?? true
24
26
  this.placeholder = placeholder ?? 'Search...'
25
27
  this.clearable = clearable ?? true
@@ -221,7 +223,7 @@ class TreeselectInput {
221
223
 
222
224
  countEl.innerHTML = this.value.length === 1
223
225
  ? this.value[0].name
224
- : `${this.value.length} elements selected`
226
+ : `${this.value.length} ${this.tagsCountText}`
225
227
 
226
228
  return countEl
227
229
  }
package/src/list.js CHANGED
@@ -277,7 +277,7 @@ class TreeselectList {
277
277
 
278
278
  this.flattedOptions = getFlatOptions(this.options, this.openLevel)
279
279
  this.flattedOptionsBeforeSearch = this.flattedOptions
280
- this.selectedNodes = { ids: [], groupedIds: [] }
280
+ this.selectedNodes = { nodes: [], groupedNodes: [] }
281
281
  this.srcElement = this.#createList()
282
282
 
283
283
  this.updateValue(this.value)
@@ -654,8 +654,8 @@ class TreeselectList {
654
654
 
655
655
  #updateSelectedNodes () {
656
656
  this.selectedNodes = {
657
- ids: getCheckedValues(this.flattedOptions),
658
- groupedIds: getGroupedValues(this.flattedOptions)
657
+ nodes: getCheckedValues(this.flattedOptions),
658
+ groupedNodes: getGroupedValues(this.flattedOptions)
659
659
  }
660
660
  }
661
661
 
@@ -12,6 +12,8 @@ const validateProps = ({ parentHtmlContainer, staticList, appendToBody }) => {
12
12
  }
13
13
  }
14
14
 
15
+ const getOnlyIds = (nodes) => nodes.map(node => node.id)
16
+
15
17
  class Treeselect {
16
18
  // Components
17
19
  #htmlContainer = null
@@ -27,9 +29,6 @@ class Treeselect {
27
29
  #focusEvent = null
28
30
  #blurEvent = null
29
31
 
30
- // State
31
- #isListOpened = false
32
-
33
32
  constructor ({
34
33
  parentHtmlContainer,
35
34
  value,
@@ -38,6 +37,7 @@ class Treeselect {
38
37
  appendToBody,
39
38
  alwaysOpen,
40
39
  showTags,
40
+ tagsCountText,
41
41
  clearable,
42
42
  searchable,
43
43
  placeholder,
@@ -60,6 +60,7 @@ class Treeselect {
60
60
  this.appendToBody = appendToBody ?? true
61
61
  this.alwaysOpen = alwaysOpen && !disabled
62
62
  this.showTags = showTags ?? true
63
+ this.tagsCountText = tagsCountText ?? 'elements selected'
63
64
  this.clearable = clearable ?? true
64
65
  this.searchable = searchable ?? true
65
66
  this.placeholder = placeholder ?? 'Search...'
@@ -69,6 +70,8 @@ class Treeselect {
69
70
  this.emptyText = emptyText ?? 'No results found...'
70
71
  this.staticList = staticList && !this.appendToBody
71
72
 
73
+ // State
74
+ this.isListOpened = false
72
75
  this.srcElement = null
73
76
 
74
77
  this.mount()
@@ -97,8 +100,8 @@ class Treeselect {
97
100
  updateValue (newValue) {
98
101
  const list = this.#treeselectList
99
102
  list.updateValue(newValue)
100
- const {groupedIds, ids } = list.selectedNodes
101
- const inputNewValue = this.grouped ? groupedIds : ids
103
+ const {groupedNodes, nodes } = list.selectedNodes
104
+ const inputNewValue = this.grouped ? groupedNodes : nodes
102
105
  this.#treeselectInput.updateValue(inputNewValue)
103
106
  }
104
107
 
@@ -111,6 +114,19 @@ class Treeselect {
111
114
  }
112
115
  }
113
116
 
117
+ focus () {
118
+ if (this.#treeselectInput) {
119
+ this.#treeselectInput.focus()
120
+ }
121
+ }
122
+
123
+ toggleOpenClose () {
124
+ if (this.#treeselectInput) {
125
+ this.#treeselectInput.openClose()
126
+ this.#treeselectInput.focus()
127
+ }
128
+ }
129
+
114
130
  #createTreeselect () {
115
131
  const container = this.parentHtmlContainer
116
132
  container.classList.add('treeselect')
@@ -123,10 +139,11 @@ class Treeselect {
123
139
  emptyText: this.emptyText
124
140
  })
125
141
 
126
- const {groupedIds, ids } = list.selectedNodes
142
+ const {groupedNodes, nodes } = list.selectedNodes
127
143
  const input = new TreeselectInput({
128
- value: this.grouped ? groupedIds : ids,
144
+ value: this.grouped ? groupedNodes : nodes,
129
145
  showTags: this.showTags,
146
+ tagsCountText: this.tagsCountText,
130
147
  clearable: this.clearable,
131
148
  isAlwaysOpened: this.alwaysOpen,
132
149
  searchable: this.searchable,
@@ -142,14 +159,15 @@ class Treeselect {
142
159
 
143
160
  // Input events
144
161
  input.srcElement.addEventListener('input', (e) => {
145
- const ids = e.detail.map(({ id }) => id)
146
- this.value = ids
147
- list.updateValue(ids)
162
+ const inputIds = getOnlyIds(e.detail)
163
+ list.updateValue(inputIds)
164
+ const { nodes } = list.selectedNodes
165
+ this.value = getOnlyIds(nodes)
148
166
  this.#emitInput()
149
167
  })
150
168
  input.srcElement.addEventListener('open', () => this.#openList())
151
169
  input.srcElement.addEventListener('keydown', (e) => {
152
- if (this.#isListOpened) {
170
+ if (this.isListOpened) {
153
171
  list.callKeyAction(e.key)
154
172
  }
155
173
  })
@@ -175,10 +193,10 @@ class Treeselect {
175
193
  input.focus()
176
194
  }, true)
177
195
  list.srcElement.addEventListener('input', (e) => {
178
- const {groupedIds, ids } = e.detail
179
- const inputIds = this.grouped ? groupedIds : ids
196
+ const {groupedNodes, nodes } = e.detail
197
+ const inputIds = this.grouped ? groupedNodes : nodes
180
198
  input.updateValue(inputIds)
181
- this.value = ids.map(({ id }) => id)
199
+ this.value = getOnlyIds(nodes)
182
200
  input.focus()
183
201
  this.#emitInput()
184
202
  })
@@ -197,7 +215,7 @@ class Treeselect {
197
215
  }
198
216
 
199
217
  #openList () {
200
- this.#isListOpened = true
218
+ this.isListOpened = true
201
219
 
202
220
  window.addEventListener('scroll', this.#scrollEvent, true)
203
221
  window.addEventListener('resize', this.#resizeEvent)
@@ -215,7 +233,7 @@ class Treeselect {
215
233
  }
216
234
 
217
235
  #closeList () {
218
- this.#isListOpened = false
236
+ this.isListOpened = false
219
237
 
220
238
  window.removeEventListener('scroll', this.#scrollEvent, true)
221
239
  window.removeEventListener('resize', this.#resizeEvent)