import { FSelect, FSelectArray, FSelectOptionObject, FSelectOptionsGroup, FSelectOptionsProp, FSelectSingleOption } from "./f-select"; import { html } from "lit"; import { classMap } from "lit-html/directives/class-map.js"; import { unsafeSVG } from "lit-html/directives/unsafe-svg.js"; import loader from "../../mixins/svg/loader"; export default function render(this: FSelect) { this.validateProperties(); let selectedOptionsLength = 0; if (Array.isArray(this.selectedOptions)) { selectedOptionsLength = this.selectedOptions.length; } else if (this.selectedOptions) { selectedOptionsLength = Object.keys(this.selectedOptions).length; } let filteredOptionsLength = 0; if (Array.isArray(this.filteredOptions)) { filteredOptionsLength = this.filteredOptions.length; } else if (this.selectedOptions) { filteredOptionsLength = Object.keys(this.filteredOptions).length; } /** * apply width according to the prop */ if (this.width === "fill-container") { this.style.width = "100%"; } else { this.style.width = `${this.width}px` ?? "100%"; } /** * concaticated array from groups */ const concatinatedSelectedOptions = !Array.isArray(this.selectedOptions) ? this.getConcaticateGroupOptions(this.selectedOptions) : []; /** * create iconlLeft if available */ const iconLeft = this.iconLeft ? html` ` : ""; /** * create caret-up/caret-down icon for open/close option-menu */ const iconRight = !this.openDropdown ? html`` : html``; /** * input text area with alternate f-text placeholder when not searchable */ const inputAppend = html` ${selectedOptionsLength === 0 && concatinatedSelectedOptions?.length === 0 && !this.searchable ? html`${this.placeholder}` : ""} 0 || concatinatedSelectedOptions?.length > 0 ? this.searchable && this.openDropdown ? this.placeholder : "" : this.placeholder} size=${this.size} ?readonly=${!this.searchable} .value=${this.searchValue} @input=${this.handleInput} @blur=${this.handleBlur} style="${this.applyInputStyle()}" /> `; /** * append prefix consisting of f-tags, iiconLeft and search string */ const prefixAppend = html`
${this.iconLeft ? html` ${iconLeft}` : ""} ${Array.isArray(this.selectedOptions) && selectedOptionsLength > 0 ? html`
${this.type === "single" ? this.selectedOptions.map(option => this.renderSingleSelection(option)) : html`${this.selectedOptions .slice(0, this.getSlicedSelections(this.selectedOptions)) .map(option => this.renderMultipleSelectionTag(option))} ${this.selectedOptions.length > this.selectionLimit ? !this.viewMoreTags ? html` e.preventDefault()} >+${this.selectedOptions.length - this.selectionLimit} more` : html` e.preventDefault()} >show less` : ""} `} ${inputAppend}
` : html`
${this.type === "single" ? (concatinatedSelectedOptions as FSelectOptionsProp).map(option => this.renderSingleSelection(option) ) : html` ${(concatinatedSelectedOptions as FSelectOptionsProp) .slice(0, this.getSlicedSelections(concatinatedSelectedOptions)) .map(option => this.renderMultipleSelectionTag(option))} ${concatinatedSelectedOptions.length > this.selectionLimit ? !this.viewMoreTags ? html` e.preventDefault()} >+${concatinatedSelectedOptions.length - this.selectionLimit} more` : html` e.preventDefault()} >show less` : ""}`} ${inputAppend}
`}
`; /** * append suffix consisting of clear icon caret-up/caret-down icon and loader */ const suffixAppend = !this.loading ? html`
${(selectedOptionsLength > 0 || concatinatedSelectedOptions?.length > 0) && this.clear ? html` Array.isArray(this.selectedOptions) ? this.clearInputValue(e) : this.clearSelectionInGroups(e)} class=${!this.size ? "f-input-icons-size" : ""} > ` : ""} ${iconRight}
` : html`
${unsafeSVG(loader)}
`; /** * empty filtered options */ const emptyMenu = html` { e.stopImmediatePropagation(); e.stopPropagation(); }} > No Options found. ${this.createOption && this.searchValue && this.searchable ? html` this.createNewOption(e)} > ${this.offsetWidth > 200 ? html` ` : html``} ` : ""} `; /** * Final html to render */ return html`
{ this.handleDropDownClose(e); }} >
${prefixAppend} ${suffixAppend}
${Array.isArray(this.options) ? filteredOptionsLength > 0 ? (this.filteredOptions as FSelectArray)?.map( option => html` { this.handleOptionSelection(option, e); }} @mouseover=${(e: MouseEvent) => { this.handleOptionMouseOver(e); }} .disabled=${typeof option === "object" && option.disabled} > ${this.checkbox ? html` { this.handleCheckboxInput(option, e); }} >` : ""} ${(option as FSelectOptionObject)?.icon && !this.optionTemplate ? html` ` : ""} ${this.optionTemplate ? this.optionTemplate(option) : ""} ${!this.optionTemplate ? html` ${(option as FSelectOptionObject)?.title ?? option}` : ""} ${this.isSelected(option) && !this.checkbox ? html` ` : ""} ` ) : emptyMenu : Object.keys(this.filteredOptions)?.length > 0 && Object.keys(this.filteredOptions)?.every( groupName => (this.filteredOptions as FSelectOptionsGroup)[groupName].length > 0 ) ? Object.keys(this.filteredOptions)?.map(group => (this.filteredOptions as FSelectOptionsGroup)[group].length > 0 ? html` this.handleSelectAll(e, group)} > ${ this.checkbox ? html` this.handleSelectAll(e, group)} >` : "" } ${group} ${(this.filteredOptions as FSelectOptionsGroup)[group].map( option => html` { this.handleSelectionGroup(option, group, e); }} @mouseover=${(e: MouseEvent) => { this.handleOptionMouseOver(e); }} .disabled=${typeof option === "object" && option.disabled} > ${this.checkbox ? html` { this.handleCheckboxGroup(option, group, e); }} >` : ""} ${(option as FSelectOptionObject)?.icon && !this.optionTemplate ? html` ` : ""} ${this.optionTemplate ? this.optionTemplate(option) : ""} ${!this.optionTemplate ? html` ${(option as FSelectOptionObject)?.title ?? option}` : ""} ${this.isGroupSelection(option, group) && !this.checkbox ? html` ` : ""} ` )} ` : "" ) : emptyMenu}
`; } export function renderSingleSelection(this: FSelect, option: FSelectSingleOption) { // when user accidently pass array of options in single selection if (Array.isArray(option)) { option = option[0]; } const withoutTemplate = () => { return html` ${(option as FSelectOptionObject)?.title ?? option}`; }; const getTemplate = () => { return this.optionTemplate ? this.optionTemplate(option, true) : withoutTemplate(); }; return html` ${getTemplate()} `; } export function renderMultipleSelectionTag(this: FSelect, option: FSelectSingleOption) { const withoutTemplate = () => { return html` { this.handleOptionSelection(option, e); }} > `; }; const getTemplate = () => { return this.optionTemplate ? html`${this.optionTemplate(option, true)} { this.handleOptionSelection(option, e); }} category="packed" > ` : withoutTemplate(); }; return getTemplate(); }