import { css as litCss, LitElement } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { html, nothing } from 'lit/html.js'; import { css } from 'twind/css'; import { createUUID } from './utils/UniqueId'; import { MonoTextComp } from './MonoTextComp'; import { fromOptionalConverter, spread } from './utils/LitHelper'; import { SpreadController } from './utils/SpreadController'; import { TailwindStylesController } from './utils/TailwindStylesController'; import { RoundedCorners } from './utils/CommonTypes'; export type SelectOption = { selected?: boolean; disabled?: boolean; hidden?: boolean; value: string; text: string; }; @customElement('mono-select') export class MonoSelectComp extends LitElement { static styles = litCss` ::slotted(p:first-of-type) { margin: 0; } `; private __spreadController: SpreadController = new SpreadController(this); private __stylesController: TailwindStylesController = new TailwindStylesController( this, ); @property({ type: String, reflect: true }) value: string = ''; @property({ type: Array, reflect: true }) options: SelectOption[] = []; @property({ type: String, reflect: true }) id: string = createUUID(); @property({ type: String, reflect: true }) name: string = ''; @property({ type: String, reflect: true, converter: fromOptionalConverter }) error?: string; @property({ type: Boolean, reflect: true }) disabled: boolean = false; @property({ type: Boolean, reflect: true }) required: boolean = false; @property({ type: String, reflect: true }) corners: RoundedCorners = 'none'; @query('select', true) __selectEl!: HTMLSelectElement; @query('label', true) __labelEl!: HTMLLabelElement; @query('[id*="-errors"]', true) __errorEl!: MonoTextComp; private __onBlur(_event: Event) { this.value = this.__selectEl.value; } private __onInput(_event: Event) { this.value = this.__selectEl.value; } private __onChange(event: Event) { event.preventDefault(); event.stopPropagation(); this.value = this.__selectEl.value; const changeEvent = new CustomEvent('change', { detail: { value: this.value }, bubbles: true, composed: true, }); this.dispatchEvent(changeEvent); } private __hasError() { return this.error && this.error.length > 0; } private __renderError(ariaDescribedBy: string) { if (this.__hasError()) { return html` ${this.error} `; } return nothing; } render() { const selectOverrides = css({ 'background-image': `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`, 'background-position': 'right 0.5rem center', 'background-repeat': 'no-repeat', 'background-size': '1.5em 1.5em', 'padding-right': '2.5rem', '-webkit-print-color-adjust': 'exact', 'color-adjust': 'exact', }); const ariaDescribedBy = this.__hasError() ? `${this.id}-errors` : ''; const attributesToSpread = this.__spreadController.buildSpreadAttributesIgnoring( [ 'as', 'style', 'class', 'slot', 'value', 'options', 'id', 'name', 'error', 'disabled', 'required', 'aria-describedby', 'corners', ], ); return html`
${this.__renderError(ariaDescribedBy)}
`; } } declare global { interface HTMLElementTagNameMap { 'mono-select': MonoSelectComp; } }