ha-frontend/src/components/ha-selector/ha-selector-text.ts

157 lines
4.6 KiB
TypeScript

import { mdiEye, mdiEyeOff } from "@mdi/js";
import { CSSResultGroup, LitElement, css, html } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ensureArray } from "../../common/array/ensure-array";
import { fireEvent } from "../../common/dom/fire_event";
import { StringSelector } from "../../data/selector";
import { HomeAssistant } from "../../types";
import "../ha-icon-button";
import "../ha-multi-textfield";
import "../ha-textarea";
import "../ha-textfield";
@customElement("ha-selector-text")
export class HaTextSelector extends LitElement {
@property({ attribute: false }) public hass?: HomeAssistant;
@property() public value?: any;
@property() public name?: string;
@property() public label?: string;
@property() public placeholder?: string;
@property() public helper?: string;
@property({ attribute: false }) public selector!: StringSelector;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = true;
@state() private _unmaskedPassword = false;
public async focus() {
await this.updateComplete;
(
this.renderRoot.querySelector("ha-textarea, ha-textfield") as HTMLElement
)?.focus();
}
protected render() {
if (this.selector.text?.multiple) {
return html`
<ha-multi-textfield
.hass=${this.hass}
.value=${ensureArray(this.value ?? [])}
.disabled=${this.disabled}
.label=${this.label}
.inputType=${this.selector.text?.type}
.inputSuffix=${this.selector.text?.suffix}
.inputPrefix=${this.selector.text?.prefix}
.autocomplete=${this.selector.text?.autocomplete}
@value-changed=${this._handleChange}
>
</ha-multi-textfield>
`;
}
if (this.selector.text?.multiline) {
return html`<ha-textarea
.name=${this.name}
.label=${this.label}
.placeholder=${this.placeholder}
.value=${this.value || ""}
.helper=${this.helper}
helperPersistent
.disabled=${this.disabled}
@input=${this._handleChange}
autocapitalize="none"
.autocomplete=${this.selector.text?.autocomplete}
spellcheck="false"
.required=${this.required}
autogrow
></ha-textarea>`;
}
return html`<ha-textfield
.name=${this.name}
.value=${this.value || ""}
.placeholder=${this.placeholder || ""}
.helper=${this.helper}
helperPersistent
.disabled=${this.disabled}
.type=${this._unmaskedPassword ? "text" : this.selector.text?.type}
@input=${this._handleChange}
.label=${this.label || ""}
.prefix=${this.selector.text?.prefix}
.suffix=${this.selector.text?.type === "password"
? // reserve some space for the icon.
html`<div style="width: 24px"></div>`
: this.selector.text?.suffix}
.required=${this.required}
.autocomplete=${this.selector.text?.autocomplete}
></ha-textfield>
${this.selector.text?.type === "password"
? html`<ha-icon-button
toggles
.label=${this.hass?.localize(
this._unmaskedPassword
? "ui.components.selectors.text.hide_password"
: "ui.components.selectors.text.show_password"
) || (this._unmaskedPassword ? "Hide password" : "Show password")}
@click=${this._toggleUnmaskedPassword}
.path=${this._unmaskedPassword ? mdiEyeOff : mdiEye}
></ha-icon-button>`
: ""}`;
}
private _toggleUnmaskedPassword(): void {
this._unmaskedPassword = !this._unmaskedPassword;
}
private _handleChange(ev) {
let value = ev.detail?.value ?? ev.target.value;
if (this.value === value) {
return;
}
if (
(value === "" || (Array.isArray(value) && value.length === 0)) &&
!this.required
) {
value = undefined;
}
fireEvent(this, "value-changed", { value });
}
static get styles(): CSSResultGroup {
return css`
:host {
display: block;
position: relative;
}
ha-textarea,
ha-textfield {
width: 100%;
}
ha-icon-button {
position: absolute;
top: 8px;
right: 8px;
inset-inline-start: initial;
inset-inline-end: 8px;
--mdc-icon-button-size: 40px;
--mdc-icon-size: 20px;
color: var(--secondary-text-color);
direction: var(--direction);
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-selector-text": HaTextSelector;
}
}