@umbraco-ui/uui-select
Version:
Umbraco UI select component
280 lines (268 loc) • 8 kB
JavaScript
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 };