diff --git a/src/components/ha-aliases-editor.ts b/src/components/ha-aliases-editor.ts
index 21ec5f0e4e..e466b60123 100644
--- a/src/components/ha-aliases-editor.ts
+++ b/src/components/ha-aliases-editor.ts
@@ -1,12 +1,8 @@
-import "@material/mwc-button/mwc-button";
-import { mdiDeleteOutline, mdiPlus } from "@mdi/js";
-import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
+import { LitElement, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
-import { haStyle } from "../resources/styles";
-import { HomeAssistant } from "../types";
-import "./ha-textfield";
-import type { HaTextField } from "./ha-textfield";
import { fireEvent } from "../common/dom/fire_event";
+import { HomeAssistant } from "../types";
+import "./ha-multi-textfield";
@customElement("ha-aliases-editor")
class AliasesEditor extends LitElement {
@@ -22,107 +18,23 @@ class AliasesEditor extends LitElement {
}
return html`
- ${this.aliases.map(
- (alias, index) => html`
-
-
-
-
- `
- )}
-
-
- ${this.hass!.localize("ui.dialogs.aliases.add_alias")}
-
-
-
+
+
`;
}
- private async _addAlias() {
- this.aliases = [...this.aliases, ""];
- this._fireChanged(this.aliases);
- await this.updateComplete;
- const field = this.shadowRoot?.querySelector(`ha-textfield[data-last]`) as
- | HaTextField
- | undefined;
- field?.focus();
- }
-
- private async _editAlias(ev: Event) {
- const index = (ev.target as any).index;
- const aliases = [...this.aliases];
- aliases[index] = (ev.target as any).value;
- this._fireChanged(aliases);
- }
-
- private async _keyDownAlias(ev: KeyboardEvent) {
- if (ev.key === "Enter") {
- ev.stopPropagation();
- this._addAlias();
- }
- }
-
- private async _removeAlias(ev: Event) {
- const index = (ev.target as any).index;
- const aliases = [...this.aliases];
- aliases.splice(index, 1);
- this._fireChanged(aliases);
- }
-
- private _fireChanged(value) {
+ private _aliasesChanged(value) {
fireEvent(this, "value-changed", { value });
}
-
- static get styles(): CSSResultGroup {
- return [
- haStyle,
- css`
- .row {
- margin-bottom: 8px;
- }
- ha-textfield {
- display: block;
- }
- ha-icon-button {
- display: block;
- }
- mwc-button {
- margin-left: 8px;
- }
- #alias_input {
- margin-top: 8px;
- }
- .alias {
- border: 1px solid var(--divider-color);
- border-radius: 4px;
- margin-top: 4px;
- --mdc-icon-button-size: 24px;
- }
- `,
- ];
- }
}
declare global {
diff --git a/src/components/ha-multi-textfield.ts b/src/components/ha-multi-textfield.ts
new file mode 100644
index 0000000000..c16bfb02ad
--- /dev/null
+++ b/src/components/ha-multi-textfield.ts
@@ -0,0 +1,144 @@
+import { mdiDeleteOutline, mdiPlus } from "@mdi/js";
+import { CSSResultGroup, LitElement, css, html } from "lit";
+import { customElement, property } from "lit/decorators";
+import { fireEvent } from "../common/dom/fire_event";
+import { haStyle } from "../resources/styles";
+import type { HomeAssistant } from "../types";
+import "./ha-button";
+import "./ha-textfield";
+import type { HaTextField } from "./ha-textfield";
+
+@customElement("ha-multi-textfield")
+class HaMultiTextField extends LitElement {
+ @property({ attribute: false }) public hass?: HomeAssistant;
+
+ @property({ attribute: false }) public value?: string[];
+
+ @property({ type: Boolean }) public disabled = false;
+
+ @property() public label?: string;
+
+ @property() public inputType?: string;
+
+ @property() public inputSuffix?: string;
+
+ @property() public inputPrefix?: string;
+
+ @property() public autocomplete?: string;
+
+ @property() public addLabel?: string;
+
+ @property() public removeLabel?: string;
+
+ @property({ attribute: "item-index", type: Boolean })
+ public itemIndex?: boolean;
+
+ protected render() {
+ return html`
+ ${this._items.map((item, index) => {
+ const indexSuffix = `${this.itemIndex ? ` ${index + 1}` : ""}`;
+ return html`
+
+
+
+
+ `;
+ })}
+
+
+ ${this.addLabel ?? this.hass?.localize("ui.common.add") ?? "Add"}
+
+
+
+ `;
+ }
+
+ private get _items() {
+ return this.value ?? [];
+ }
+
+ private async _addItem() {
+ const items = [...this._items, ""];
+ this._fireChanged(items);
+ await this.updateComplete;
+ const field = this.shadowRoot?.querySelector(`ha-textfield[data-last]`) as
+ | HaTextField
+ | undefined;
+ field?.focus();
+ }
+
+ private async _editItem(ev: Event) {
+ const index = (ev.target as any).index;
+ const items = [...this._items];
+ items[index] = (ev.target as any).value;
+ this._fireChanged(items);
+ }
+
+ private async _keyDown(ev: KeyboardEvent) {
+ if (ev.key === "Enter") {
+ ev.stopPropagation();
+ this._addItem();
+ }
+ }
+
+ private async _removeItem(ev: Event) {
+ const index = (ev.target as any).index;
+ const items = [...this._items];
+ items.splice(index, 1);
+ this._fireChanged(items);
+ }
+
+ private _fireChanged(value) {
+ this.value = value;
+ fireEvent(this, "value-changed", { value });
+ }
+
+ static get styles(): CSSResultGroup {
+ return [
+ haStyle,
+ css`
+ .row {
+ margin-bottom: 8px;
+ }
+ ha-textfield {
+ display: block;
+ }
+ ha-icon-button {
+ display: block;
+ }
+ ha-button {
+ margin-left: 8px;
+ }
+ `,
+ ];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-multi-textfield": HaMultiTextField;
+ }
+}
diff --git a/src/components/ha-selector/ha-selector-text.ts b/src/components/ha-selector/ha-selector-text.ts
index 3629ba3e22..6d175017a4 100644
--- a/src/components/ha-selector/ha-selector-text.ts
+++ b/src/components/ha-selector/ha-selector-text.ts
@@ -1,10 +1,12 @@
import { mdiEye, mdiEyeOff } from "@mdi/js";
-import { css, CSSResultGroup, html, LitElement } from "lit";
+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";
@@ -38,6 +40,22 @@ export class HaTextSelector extends LitElement {
}
protected render() {
+ if (this.selector.text?.multiple) {
+ return html`
+
+
+ `;
+ }
if (this.selector.text?.multiline) {
return html`