mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-08 10:29:37 +00:00
193 lines
5.5 KiB
TypeScript
193 lines
5.5 KiB
TypeScript
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
|
import type { ComboBoxLightOpenedChangedEvent } from "@vaadin/combo-box/vaadin-combo-box-light";
|
|
import { css, html, LitElement, nothing, type CSSResultGroup } from "lit";
|
|
import { customElement, property, query, state } from "lit/decorators";
|
|
import { ifDefined } from "lit/directives/if-defined";
|
|
import { fireEvent } from "../common/dom/fire_event";
|
|
import type { HomeAssistant } from "../types";
|
|
import "./ha-combo-box-item";
|
|
import "./ha-icon-button";
|
|
import "./ha-input-helper-text";
|
|
import "./ha-picker-combo-box";
|
|
import type {
|
|
HaPickerComboBox,
|
|
PickerComboBoxItem,
|
|
PickerComboBoxSearchFn,
|
|
} from "./ha-picker-combo-box";
|
|
import "./ha-picker-field";
|
|
import type { HaPickerField, PickerValueRenderer } from "./ha-picker-field";
|
|
import "./ha-svg-icon";
|
|
|
|
@customElement("ha-generic-picker")
|
|
export class HaGenericPicker extends LitElement {
|
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
|
|
// eslint-disable-next-line lit/no-native-attributes
|
|
@property({ type: Boolean }) public autofocus = false;
|
|
|
|
@property({ type: Boolean }) public disabled = false;
|
|
|
|
@property({ type: Boolean }) public required = false;
|
|
|
|
@property({ type: Boolean, attribute: "allow-custom-value" })
|
|
public allowCustomValue;
|
|
|
|
@property() public label?: string;
|
|
|
|
@property() public value?: string;
|
|
|
|
@property() public helper?: string;
|
|
|
|
@property() public placeholder?: string;
|
|
|
|
@property({ type: String, attribute: "search-label" })
|
|
public searchLabel?: string;
|
|
|
|
@property({ attribute: "hide-clear-icon", type: Boolean })
|
|
public hideClearIcon = false;
|
|
|
|
@property({ attribute: false, type: Array })
|
|
public getItems?: () => PickerComboBoxItem[];
|
|
|
|
@property({ attribute: false, type: Array })
|
|
public getAdditionalItems?: (searchString?: string) => PickerComboBoxItem[];
|
|
|
|
@property({ attribute: false })
|
|
public rowRenderer?: ComboBoxLitRenderer<PickerComboBoxItem>;
|
|
|
|
@property({ attribute: false })
|
|
public valueRenderer?: PickerValueRenderer;
|
|
|
|
@property({ attribute: false })
|
|
public searchFn?: PickerComboBoxSearchFn<PickerComboBoxItem>;
|
|
|
|
@property({ attribute: "not-found-label", type: String })
|
|
public notFoundLabel?: string;
|
|
|
|
@query("ha-picker-field") private _field?: HaPickerField;
|
|
|
|
@query("ha-picker-combo-box") private _comboBox?: HaPickerComboBox;
|
|
|
|
@state() private _opened = false;
|
|
|
|
protected render() {
|
|
return html`
|
|
${this.label
|
|
? html`<label ?disabled=${this.disabled}>${this.label}</label>`
|
|
: nothing}
|
|
<div class="container">
|
|
${!this._opened
|
|
? html`
|
|
<ha-picker-field
|
|
type="button"
|
|
compact
|
|
aria-label=${ifDefined(this.label)}
|
|
@click=${this.open}
|
|
@clear=${this._clear}
|
|
.placeholder=${this.placeholder}
|
|
.value=${this.value}
|
|
.required=${this.required}
|
|
.disabled=${this.disabled}
|
|
.hideClearIcon=${this.hideClearIcon}
|
|
.valueRenderer=${this.valueRenderer}
|
|
>
|
|
</ha-picker-field>
|
|
`
|
|
: html`
|
|
<ha-picker-combo-box
|
|
.hass=${this.hass}
|
|
.autofocus=${this.autofocus}
|
|
.allowCustomValue=${this.allowCustomValue}
|
|
.label=${this.searchLabel ??
|
|
this.hass.localize("ui.common.search")}
|
|
.value=${this.value}
|
|
hide-clear-icon
|
|
@opened-changed=${this._openedChanged}
|
|
@value-changed=${this._valueChanged}
|
|
.rowRenderer=${this.rowRenderer}
|
|
.notFoundLabel=${this.notFoundLabel}
|
|
.getItems=${this.getItems}
|
|
.getAdditionalItems=${this.getAdditionalItems}
|
|
.searchFn=${this.searchFn}
|
|
></ha-picker-combo-box>
|
|
`}
|
|
</div>
|
|
${this._renderHelper()}
|
|
`;
|
|
}
|
|
|
|
private _renderHelper() {
|
|
return this.helper
|
|
? html`<ha-input-helper-text .disabled=${this.disabled}
|
|
>${this.helper}</ha-input-helper-text
|
|
>`
|
|
: nothing;
|
|
}
|
|
|
|
private _valueChanged(ev: CustomEvent) {
|
|
ev.stopPropagation();
|
|
const value = ev.detail.value;
|
|
if (!value) {
|
|
return;
|
|
}
|
|
fireEvent(this, "value-changed", { value });
|
|
}
|
|
|
|
private _clear(e) {
|
|
e.stopPropagation();
|
|
this._setValue(undefined);
|
|
}
|
|
|
|
private _setValue(value: string | undefined) {
|
|
this.value = value;
|
|
fireEvent(this, "value-changed", { value });
|
|
}
|
|
|
|
public async open() {
|
|
if (this.disabled) {
|
|
return;
|
|
}
|
|
this._opened = true;
|
|
await this.updateComplete;
|
|
this._comboBox?.focus();
|
|
this._comboBox?.open();
|
|
}
|
|
|
|
private async _openedChanged(ev: ComboBoxLightOpenedChangedEvent) {
|
|
const opened = ev.detail.value;
|
|
if (this._opened && !opened) {
|
|
this._opened = false;
|
|
await this.updateComplete;
|
|
this._field?.focus();
|
|
}
|
|
}
|
|
|
|
static get styles(): CSSResultGroup {
|
|
return [
|
|
css`
|
|
.container {
|
|
position: relative;
|
|
display: block;
|
|
}
|
|
label[disabled] {
|
|
color: var(--mdc-text-field-disabled-ink-color, rgba(0, 0, 0, 0.6));
|
|
}
|
|
label {
|
|
display: block;
|
|
margin: 0 0 8px;
|
|
}
|
|
ha-input-helper-text {
|
|
display: block;
|
|
margin: 8px 0 0;
|
|
}
|
|
`,
|
|
];
|
|
}
|
|
}
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
"ha-generic-picker": HaGenericPicker;
|
|
}
|
|
}
|