@oslokommune/punkt-elements
Version:
Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo
96 lines (95 loc) • 10.7 kB
JavaScript
"use strict";const s=require("./element-6DBpyGQm.cjs"),p=require("./state-DPobt-Yz.cjs"),h=require("./if-defined-Cni-RHLS.cjs"),u=require("./repeat-CDsZqct8.cjs"),c=require("./class-map-BBG2gMX4.cjs"),d=require("./stringutils-CkVRq4jP.cjs");var b=Object.defineProperty,f=Object.getOwnPropertyDescriptor,n=(r,e,t,i)=>{for(var a=i>1?void 0:i?f(e,t):e,o=r.length-1,l;o>=0;o--)(l=r[o])&&(a=(i?l(e,t,a):l(a))||a);return i&&a&&b(e,t,a),a};exports.PktListbox=class extends s.PktElement{constructor(){super(...arguments),this.id=d.uuidish(),this.label=null,this.options=[],this.isOpen=!1,this.disabled=!1,this.includeSearch=!1,this.isMultiSelect=!1,this.allowUserInput=!1,this.maxIsReached=!1,this.customUserInput=null,this.searchPlaceholder=null,this.searchValue=null,this.maxLength=0,this.userMessage=null,this._selectedOptions=0,this._filteredOptions=[]}connectedCallback(){super.connectedCallback(),this.includeSearch&&!this.searchValue&&(this.searchValue=""),this.options.length>0&&this.filterOptions(),this.setAttribute("tabindex","-1"),this.addEventListener("focus",this.focusFirstOrSelectedOption)}updated(e){(e.has("options")||e.has("searchValue"))&&this.filterOptions(),super.updated(e)}attributeChangedCallback(e,t,i){(e==="options"||e==="searchValue"||e==="search-value")&&this.filterOptions(),super.attributeChangedCallback(e,t,i)}render(){return s.x`
<div
class=${c.e({"pkt-listbox":!0,"pkt-listbox__open":this.isOpen,"pkt-txt-16-light":!0})}
role="listbox"
aria-label=${h.o(this.label)}
>
<div class="pkt-listbox__banners">
${this.renderMaximumReachedBanner()} ${this.renderUserMessage()}
${this.renderNewOptionBanner()} ${this.renderSearch()}
</div>
<ul class="pkt-listbox__options" role="presentation">
${this.renderList()}
</ul>
</div>
`}renderCheckboxOrCheckIcon(e,t){return this.isMultiSelect?s.x`
<input
class="pkt-input-check__input-checkbox"
type="checkbox"
role="presentation"
tabindex="-1"
value=${e.value}
.checked=${e.selected}
aria-labelledby=${this.id+"-option-label-"+t}
?disabled=${this.disabled||e.disabled||this.maxIsReached&&!e.selected}
/>
`:e.selected?s.x`<pkt-icon name="check-big"></pkt-icon>`:s.E}renderList(){return s.x`
${u.c(this._filteredOptions,e=>e.value,(e,t)=>s.x`
<li
=${()=>{this.toggleOption(e)}}
aria-selected=${e.selected?"true":"false"}
=${this.handleOptionKeydown}
class=${c.e({"pkt-listbox__option":!0,"pkt-listbox__option--selected":!!(!this.isMultiSelect&&e.selected),"pkt-listbox__option--checkBox":this.isMultiSelect})}
tabindex="${this.disabled||e.disabled?"-1":"0"}"
data-index=${t}
data-value=${e.value}
data-selected=${e.selected?"true":"false"}
?data-disabled=${this.disabled||e.disabled||this.maxIsReached&&!e.selected}
role="option"
id=${`${this.id}-${t}`}
>
${this.renderCheckboxOrCheckIcon(e,t)}
<span class="pkt-listbox__option-label" id=${this.id+"-option-label-"+t}>
${e.prefix?s.x`<span class="pkt-listbox__option-prefix">${e.prefix}</span>`:s.E}
${e.label||e.value}
</span>
${e.description?s.x`<span class="pkt-listbox__option-description pkt-txt-14-light"
>${e.description}</span
>`:s.E}
</li>
`)}
`}renderNewOptionBanner(){return this.allowUserInput&&this.customUserInput?s.x`
<div
class="pkt-listbox__banner pkt-listbox__banner--new-option pkt-listbox__option"
data-type="new-option"
data-value=${this.customUserInput}
data-selected="false"
tabindex="0"
=${()=>this.toggleOption({value:this.customUserInput||""})}
=${this.handleOptionKeydown}
>
<pkt-icon class="pkt-listbox__banner-icon" name="plus-sign" size="large"></pkt-icon>
Legg til “${this.customUserInput}”
</div>
`:s.E}renderMaximumReachedBanner(){return this._selectedOptions=this.options.filter(e=>e.selected).length,this.isMultiSelect&&this._selectedOptions>0&&this.maxLength>0?s.x`
<div class="pkt-listbox__banner pkt-listbox__banner--maximum-reached">
${this._selectedOptions} av maks ${this.maxLength} mulige er valgt.
</div>
`:s.E}renderUserMessage(){return this.userMessage?s.x`<div class="pkt-listbox__banner pkt-listbox__banner--user-message">
<pkt-icon
class="pkt-listbox__banner-icon"
name="exclamation-mark-circle"
size="large"
></pkt-icon>
${this.userMessage}
</div>`:s.E}renderSearch(){return this.includeSearch?s.x`
<div class="pkt-listbox__search">
<span class="pkt-listbox__search-icon">
<pkt-icon name="magnifying-glass-small" size="large"></pkt-icon>
</span>
<input
class="pkt-txt-16-light"
type="text"
aria-label="Søk i listen"
form=""
placeholder=${this.searchPlaceholder||s.translations.forms.search.placeholder}
=${this.handleSearchInput}
=${this.handleSearchKeydown}
.value=${this.searchValue}
data-type="searchbox"
?disabled=${this.disabled}
?readonly=${this.disabled}
role="searchbox"
/>
</div>
`:s.E}handleSearchInput(e){this.searchValue=e.target.value,this.dispatchEvent(new CustomEvent("search",{detail:this.searchValue,bubbles:!1}))}handleSearchKeydown(e){switch(e.key){case"Enter":e.preventDefault();break;case"ArrowUp":case"Escape":this.closeOptions(),e.preventDefault();break;case"ArrowDown":case"Tab":this.focusFirstOrSelectedOption();break}}handleOptionKeydown(e){const t=e.currentTarget,i=t.dataset.value,a=t.dataset.type,o=t.dataset.selected==="true";if(!(!this.getOptionElements().length&&(!this.customUserInput||!this.allowUserInput&&this.customUserInput)&&a!=="new-option"&&a!=="searchbox"))switch(e.key){case" ":case"Enter":this.toggleOption(t),e.preventDefault();break;case"Backspace":i&&(o?this.toggleOption(t):this.closeOptions()),e.preventDefault();break;case"Escape":case"Tab":this.closeOptions();break;case"ArrowDown":e.altKey?this.focusLastOption():a==="searchbox"||a==="new-option"?this.focusFirstOption():this.focusNextOption(t),e.preventDefault();break;case"ArrowUp":if(e.altKey)this.focusFirstOption();else if(t.dataset.index==="0"&&this.includeSearch){const l=this.querySelector('[role="searchbox"]');l&&l.focus()}else if(t.dataset.index==="0"&&this.customUserInput){const l=this.querySelector('[data-type="new-option"]');l&&l.focus()}else this.focusPreviousOption(t);e.preventDefault();break;case"Home":this.focusFirstOption(),e.preventDefault();break;case"End":this.focusLastOption(),e.preventDefault();break;default:(e.metaKey||e.ctrlKey)&&e.key==="a"&&(this.selectAll(),e.preventDefault()),this.isLetterOrSpace(e.key)&&(this.handleTypeAhead(e.key),e.preventDefault());break}}focusAndScrollIntoView(e){e.scrollIntoView({block:"nearest"}),window.setTimeout(()=>e.focus(),0)}focusNextOption(e){const t=e.nextElementSibling;t&&this.focusAndScrollIntoView(t)}focusPreviousOption(e){const t=e.previousElementSibling;if(e.dataset.index==="0"&&this.includeSearch){const i=this.querySelector('[role="searchbox"]');i&&this.focusAndScrollIntoView(i)}else t&&this.focusAndScrollIntoView(t)}focusFirstOption(){const e=this.getOptionElements()[0];e&&this.focusAndScrollIntoView(e)}focusLastOption(){const e=this.getOptionElements().pop();e&&this.focusAndScrollIntoView(e)}focusFirstOrSelectedOption(){if(this.disabled)return;const e=this.getOptionElements().find(t=>t.dataset.selected==="true");if(this.allowUserInput&&this.customUserInput){const t=this.querySelector('[data-type="new-option"]');this.focusAndScrollIntoView(t)}else if(e)this.focusAndScrollIntoView(e);else if(this.includeSearch&&!(document.activeElement instanceof HTMLInputElement)){const t=this.querySelector('[role="searchbox"]');window.setTimeout(()=>t.focus(),0)}else this.focusFirstOption()}toggleOption(e){const t=e instanceof HTMLElement?e.dataset.disabled:e.disabled;if(this.disabled||t)return;const i=e instanceof HTMLElement?e.dataset.value:e.value;this.dispatchEvent(new CustomEvent("option-toggle",{detail:i,bubbles:!1}))}selectAll(){this.dispatchEvent(new CustomEvent("select-all",{bubbles:!1}))}closeOptions(){this.dispatchEvent(new CustomEvent("close-options",{bubbles:!1}))}filterOptions(){this.searchValue?this._filteredOptions=this.options.filter(e=>{var i;return(e.label+e.value).toLowerCase().includes(((i=this.searchValue)==null?void 0:i.toLowerCase())||"")}):this._filteredOptions=[...this.options]}isLetterOrSpace(e){return/^[\p{L} ]$/u.test(e)}handleTypeAhead(e){this.typeAheadString+=e.toLowerCase(),this.typeAheadTimeout&&clearTimeout(this.typeAheadTimeout),this.typeAheadTimeout=window.setTimeout(()=>{this.typeAheadString=""},500);const i=this.getOptionElements().find(a=>{var o;return(o=a.textContent)==null?void 0:o.trim().toLowerCase().startsWith(this.typeAheadString)});i&&this.focusAndScrollIntoView(i)}getOptionElements(){return this._filteredOptions.length?Array.from(this.querySelectorAll('[role="option"]:not([data-disabled])')||[]):[]}};n([s.n({type:String})],exports.PktListbox.prototype,"id",2);n([s.n({type:String})],exports.PktListbox.prototype,"label",2);n([s.n({type:Array})],exports.PktListbox.prototype,"options",2);n([s.n({type:Boolean,reflect:!0})],exports.PktListbox.prototype,"isOpen",2);n([s.n({type:Boolean})],exports.PktListbox.prototype,"disabled",2);n([s.n({type:Boolean})],exports.PktListbox.prototype,"includeSearch",2);n([s.n({type:Boolean})],exports.PktListbox.prototype,"isMultiSelect",2);n([s.n({type:Boolean})],exports.PktListbox.prototype,"allowUserInput",2);n([s.n({type:Boolean})],exports.PktListbox.prototype,"maxIsReached",2);n([s.n({type:String})],exports.PktListbox.prototype,"customUserInput",2);n([s.n({type:String})],exports.PktListbox.prototype,"searchPlaceholder",2);n([s.n({type:String})],exports.PktListbox.prototype,"searchValue",2);n([s.n({type:Number})],exports.PktListbox.prototype,"maxLength",2);n([s.n({type:String})],exports.PktListbox.prototype,"userMessage",2);n([p.r()],exports.PktListbox.prototype,"_filteredOptions",2);exports.PktListbox=n([s.t("pkt-listbox")],exports.PktListbox);