Newer
Older
iuav-ui / src / components / input / select.ts
import { LitElement, html, css } from 'lit';
import { customElement, property, queryAssignedNodes } from 'lit/decorators.js';

@customElement('iu-select')

export class Select extends LitElement {
  static override styles = css`
    :host {
        display: block;
    }
    .select-group{
        margin-bottom: var(--iu-spacing-4);
    }
    label {
        font-weight: bold;
        display: block;
        margin-bottom: var(--iu-spacing-0);
    }
    .select{
        width: 100%;
        border-top: 1px solid var(--iu-color-grey-200);
        border-bottom: 1px solid var(--iu-color-grey-200);
        position: relative;
    }

    .select.has-value select {
        color: var(--iu-color-black);
    }

    select {
        width: 100%;
        height: 2.25rem;
        appearance: none;
        border: 0;
        background: transparent;
        padding: 8px 0;
        color: var(--iu-color-grey-300);
        font-size: 1rem;
        cursor: pointer;
    }

    .select:has(select:focus){
        border-top: 1px solid var(--iu-color-black);
        border-bottom: 1px solid var(--iu-color-black);
    }

    select:focus {
        outline: 0;
        color: var(--iu-color-black);
    }
    svg{
        width: 36px;
        height: 36px;
        position: absolute;
        right: 0;
        top: 0;
        pointer-events: none;
    }
  `;

  @property({ type: String }) selected = '';
  @property({ type: String }) name: string = '';
  @property({ type: String }) label?: string;
  @property({ type: String }) placeholder?: string;
  @property({ type: Array }) options: Array<{ value: string; label: string }> = [];

  @queryAssignedNodes() private slottedOptions?: NodeList;

  private handleChange(event: Event) {
    const target = event.target as HTMLSelectElement;
    this.selected = target.value;
    // Add class when an option is selected
    const selectWrapper = this.shadowRoot?.querySelector('.select');
    if (selectWrapper) {
        selectWrapper.classList.toggle('has-value', this.selected !== '');
    }    
    this.dispatchEvent(new CustomEvent('select-change', {
        detail: { value: this.selected },
        bubbles: true,
        composed: true,
    }));
  }

  override render() {
    return html`
        <div class="select-group">
            <label for="${this.name}">${this.label}</label>
            <div class="select">
                <select @change="${this.handleChange}">
                    ${this.placeholder ? html `<option selected disabled>${this.placeholder}</option>` : ''}
                    ${this.options.map(
                        option => html`<option value="${option.value}">${option.label}</option>`
                    )}
                </select>
                <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 37 37"><path fill-rule="evenodd" clip-rule="evenodd" d="m18.502 21.319 5.66-5.241.68.733-6.34 5.87-6.34-5.87.68-.733 5.66 5.24Z" fill="#000"/></svg>
            </div>
        </div>
    `;
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'iu-select': Select;
  }
}