/** * Copyright Aquera Inc 2025 * * This source code is licensed under the BSD-3-Clause license found in the * LICENSE file in the root directory of this source tree. */ import { html, type TemplateResult } from 'lit'; import { virtualize } from '@lit-labs/virtualizer/virtualize.js'; import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { classMap } from 'lit/directives/class-map.js'; export class VirtualSelectRenderer { static getVirtualizedContent( data: any[], searchEnabled: boolean, renderItemFunction: (item: any) => string, value: string | string[], multiple: boolean, getDisplayText?: (item: any) => string, getItemValue?: (item: any) => string, getItemDescription?: (item: any) => string, getItemPrefix?: (item: any) => string, getItemSuffix?: (item: any) => string, showNoResults?: boolean, noResultsMessage?: string, loading?: boolean, onScroll?: (e: Event) => void, allowHtmlLabel?: boolean, enableDescription?: boolean ): TemplateResult { return html`
${showNoResults && !loading ? html`
${noResultsMessage || 'No results found'}
` : html`
${VirtualSelectRenderer.shouldUseVirtualizer(data) ? html` ${virtualize({ items: data, renderItem: (item: any): TemplateResult => VirtualSelectRenderer.getItemRenderFunction(item, renderItemFunction, value, multiple, getDisplayText, getItemValue, getItemDescription, getItemPrefix, getItemSuffix, allowHtmlLabel, enableDescription), scroller: true, })} ` : html` ${data.map((item: any) => VirtualSelectRenderer.getItemRenderFunction(item, renderItemFunction, value, multiple, getDisplayText, getItemValue, getItemDescription, getItemPrefix, getItemSuffix, allowHtmlLabel, enableDescription) )} `}
`}
`; } static getItemRenderFunction( item: any, renderItemFunction: (item: any) => string, value: string | string[], multiple: boolean, getDisplayText?: (item: any) => string, getItemValue?: (item: any) => string, getItemDescription?: (item: any) => string, getItemPrefix?: (item: any) => string, getItemSuffix?: (item: any) => string, allowHtmlLabel?: boolean, enableDescription?: boolean, ): TemplateResult { if(!item) { return html``; } const displayTextFn = getDisplayText || renderItemFunction; const valueFn = getItemValue || ((item: any) => item?.value || item); const optionValue = valueFn(item); const displayText = displayTextFn(item); const isDisabled = item?.disabled || false; const className = item?.className; const description = (getItemDescription ? getItemDescription(item) : item?.description) ?? ''; const prefix = (getItemPrefix ? getItemPrefix(item) : item?.prefix) ?? ''; const suffix = (getItemSuffix ? getItemSuffix(item) : item?.suffix) ?? ''; let isSelected = false; if (multiple) { isSelected = Array.isArray(value) && value.some(v => String(v) === String(optionValue)); } else { isSelected = (Array.isArray(value) ? value[0] : value) === optionValue; } return html` ${unsafeHTML(prefix)} ${allowHtmlLabel ? unsafeHTML(displayText) : displayText} ${unsafeHTML(suffix)} `; } /** * Determines whether to use virtualizer based on dataset size * For small datasets (less than 5 items), use regular rendering for better sizing */ private static shouldUseVirtualizer(data: any[]): boolean { return data.length >= 5; } }