UNPKG

@umbraco-ui/uui-select

Version:

Umbraco UI select component

280 lines (268 loc) 8 kB
import { UUIFormControlMixin } from '@umbraco-ui/uui-base/lib/mixins'; import { defineElement } from '@umbraco-ui/uui-base/lib/registration'; import { LitElement, html, nothing, css } from 'lit'; import { property, state, query } from 'lit/decorators.js'; import { UUIEvent } from '@umbraco-ui/uui-base/lib/events'; class UUISelectEvent extends UUIEvent { static { this.CHANGE = "change"; } constructor(evName, eventInit = {}) { super(evName, { ...{ bubbles: true }, ...eventInit }); } } var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __decorateClass = (decorators, target, key, kind) => { var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target; for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result; if (kind && result) __defProp(target, key, result); return result; }; let UUISelectElement = class extends UUIFormControlMixin(LitElement, "") { constructor() { super(); this.placeholder = ""; this.disabled = false; this.readonly = false; this.error = false; this.options = []; this._groups = []; this.disabledGroups = ""; this._disabledGroups = []; this._values = []; this.addEventListener("mousedown", () => { this.style.setProperty("--uui-show-focus-outline", "0"); }); this.addEventListener("blur", () => { this.style.setProperty("--uui-show-focus-outline", ""); }); } /** * This method enables <label for="..."> to focus the select */ async focus() { await this.updateComplete; this._input.focus(); } async blur() { await this.updateComplete; this._input.blur(); } /** * This method enables <label for="..."> to open the select */ async click() { await this.updateComplete; this._input.click(); } getFormElement() { return this._input; } connectedCallback() { super.connectedCallback(); if (!this.label) { console.warn(this.tagName + " needs a `label`", this); } } _createDisabledGroups() { if (this.disabledGroups.length === 0) return; this._disabledGroups = this.disabledGroups.split(","); } _extractGroups() { if (this.options.length === 0) return; this._groups = Array.from( new Set( this.options.filter((option) => option.group).map((option) => option.group) ) ); } willUpdate(changedProperties) { if (changedProperties.has("options")) { this._extractGroups(); this._values = this.options.map((option) => option.value); const selected = this.options.find((option) => option.selected); this.value = selected ? selected.value : ""; } if (changedProperties.has("value")) { this.value = this._values.includes(this.value) ? this.value : ""; } if (changedProperties.has("disabledGroups")) this._createDisabledGroups(); } setValue(e) { e.stopPropagation(); const target = e.target; if (e.target) this.value = target.value; this.dispatchEvent( new UUISelectEvent(UUISelectEvent.CHANGE, { bubbles: true, composed: false }) ); } _renderOption(name, value, selected, disabled) { return html`<option value="${value}" ?selected=${selected} ?disabled=${disabled}> ${name} </option>`; } _renderGrouped() { if (this._groups.length === 0) return nothing; return html` ${this._groups.map( (group) => html`<optgroup label=${group} ?disabled=${this._disabledGroups.some( (disabled) => disabled.toLowerCase() === group.toLowerCase() )}> ${this.options.map( (option) => option.group === group ? this._renderOption( option.name, option.value, option.selected, option.disabled ) : "" )} </optgroup>` )} `; } _getDisplayValue() { return this.options.find((option) => option.value === this.value)?.name || this.value; } render() { if (this.readonly) return html`<span>${this._getDisplayValue()}</span>`; return html` <select id="native" aria-label=${this.label} @change=${this.setValue} ?disabled=${this.disabled} .name=${this.name} .value=${this.value}> <option disabled selected value="" hidden>${this.placeholder}</option> ${this._renderGrouped()} ${this.options.filter((option) => !option.group).map( (option) => this._renderOption( option.name, option.value, option.selected, option.disabled ) )} </select>`; } }; UUISelectElement.styles = [ css` :host { display: inline-block; position: relative; font-family: inherit; } #native { display: inline-block; font-family: inherit; font-size: var(--uui-select-font-size, inherit); height: var(--uui-select-height, var(--uui-size-11,33px)); padding: var(--uui-select-padding-y, var(--uui-size-1,3px)) var(--uui-select-padding-x, var(--uui-size-2,6px)); color: var(--uui-select-text-color, var(--uui-color-text,#060606)); box-sizing: border-box; border-radius: var(--uui-border-radius,3px); border: 1px solid var(--uui-select-border-color, var(--uui-color-border,#d8d7d9)); transition: all 150ms ease; width: 100%; background-color: var( --uui-select-background-color, var(--uui-color-surface,#fff) ); } #native:focus { outline: calc(2px * var(--uui-show-focus-outline, 1)) solid var(--uui-select-outline-color, var(--uui-color-focus,#3879ff)); } #native[disabled] { cursor: not-allowed; background-color: var( --uui-select-disabled-background-color, var(--uui-color-disabled,#f3f3f5) ); } #native:hover { border: 1px solid var(--uui-select-border-color-hover, var(--uui-color-border-emphasis,#a1a1a1)); } option:checked { background: var( --uui-select-selected-option-background-color, var(--uui-color-selected,#3544b1) ); color: var( --uui-select-selected-option-color, var(--uui-color-selected-contrast,#fff) ); } #caret { position: absolute; right: 12px; top: 50%; transform: translateY(-50%); } :host([error]) #native { border: 1px solid var(--uui-color-invalid-standalone,rgb( 191, 33, 78 )); } :host([error]) #native[disabled] { border: 1px solid var(--uui-color-invalid-standalone,rgb( 191, 33, 78 )); } ` ]; __decorateClass([ property({ type: String }) ], UUISelectElement.prototype, "label", 2); __decorateClass([ property() ], UUISelectElement.prototype, "placeholder", 2); __decorateClass([ property({ type: Boolean, reflect: true }) ], UUISelectElement.prototype, "disabled", 2); __decorateClass([ property({ type: Boolean, reflect: true }) ], UUISelectElement.prototype, "readonly", 2); __decorateClass([ property({ type: Boolean, reflect: true }) ], UUISelectElement.prototype, "error", 2); __decorateClass([ property({ type: Array, attribute: false }) ], UUISelectElement.prototype, "options", 2); __decorateClass([ state() ], UUISelectElement.prototype, "_groups", 2); __decorateClass([ property() ], UUISelectElement.prototype, "disabledGroups", 2); __decorateClass([ state() ], UUISelectElement.prototype, "_disabledGroups", 2); __decorateClass([ query("#native") ], UUISelectElement.prototype, "_input", 2); UUISelectElement = __decorateClass([ defineElement("uui-select") ], UUISelectElement); export { UUISelectElement, UUISelectEvent };