Files
frontend/src/components/ha-form/ha-form-string.ts
2022-04-29 11:50:19 +02:00

149 lines
3.7 KiB
TypeScript

import { mdiEye, mdiEyeOff } from "@mdi/js";
import {
css,
CSSResultGroup,
html,
LitElement,
PropertyValues,
TemplateResult,
} from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import "../ha-icon-button";
import "../ha-textfield";
import type { HaTextField } from "../ha-textfield";
import type {
HaFormElement,
HaFormStringData,
HaFormStringSchema,
} from "./types";
const MASKED_FIELDS = ["password", "secret", "token"];
@customElement("ha-form-string")
export class HaFormString extends LitElement implements HaFormElement {
@property() public schema!: HaFormStringSchema;
@property() public data!: HaFormStringData;
@property() public label!: string;
@property() public helper?: string;
@property({ type: Boolean }) public disabled = false;
@state() private _unmaskedPassword = false;
@query("ha-textfield") private _input?: HaTextField;
public focus(): void {
if (this._input) {
this._input.focus();
}
}
protected render(): TemplateResult {
const isPassword = MASKED_FIELDS.some((field) =>
this.schema.name.includes(field)
);
return html`
<ha-textfield
.type=${!isPassword
? this._stringType
: this._unmaskedPassword
? "text"
: "password"}
.label=${this.label}
.value=${this.data || ""}
.helper=${this.helper}
helperPersistent
.disabled=${this.disabled}
.required=${this.schema.required}
.autoValidate=${this.schema.required}
.suffix=${isPassword
? // reserve some space for the icon.
html`<div style="width: 24px"></div>`
: this.schema.description?.suffix}
.validationMessage=${this.schema.required ? "Required" : undefined}
@input=${this._valueChanged}
></ha-textfield>
${isPassword
? html`<ha-icon-button
toggles
.label=${`${this._unmaskedPassword ? "Hide" : "Show"} password`}
@click=${this._toggleUnmaskedPassword}
.path=${this._unmaskedPassword ? mdiEyeOff : mdiEye}
></ha-icon-button>`
: ""}
`;
}
protected updated(changedProps: PropertyValues): void {
if (changedProps.has("schema")) {
this.toggleAttribute("own-margin", !!this.schema.required);
}
}
private _toggleUnmaskedPassword(): void {
this._unmaskedPassword = !this._unmaskedPassword;
}
private _valueChanged(ev: Event): void {
let value: string | undefined = (ev.target as HaTextField).value;
if (this.data === value) {
return;
}
if (value === "" && !this.schema.required) {
value = undefined;
}
fireEvent(this, "value-changed", {
value,
});
}
private get _stringType(): string {
if (this.schema.format) {
if (["email", "url"].includes(this.schema.format)) {
return this.schema.format;
}
if (this.schema.format === "fqdnurl") {
return "url";
}
}
return "text";
}
static get styles(): CSSResultGroup {
return css`
:host {
display: block;
position: relative;
}
:host([own-margin]) {
margin-bottom: 5px;
}
ha-textfield {
display: block;
}
ha-icon-button {
position: absolute;
top: 1em;
right: 12px;
--mdc-icon-button-size: 24px;
color: var(--secondary-text-color);
}
:host-context([style*="direction: rtl;"]) ha-icon-button {
right: auto;
left: 12px;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-form-string": HaFormString;
}
}