From 4bdac1f3858c315a14a6bc61b58c9d919aa19096 Mon Sep 17 00:00:00 2001 From: Wendelin <12148533+wendevlin@users.noreply.github.com> Date: Tue, 24 Mar 2026 14:18:09 +0100 Subject: [PATCH] Migrate form/selector components ha-textfield to ha-input (#30294) * Migrate ha-textfield to ha-input across form components and update related logic * Apply suggestions from code review Co-authored-by: Petar Petrov --------- Co-authored-by: Petar Petrov --- src/components/ha-form/ha-form-float.ts | 36 ++++++++++--------- src/components/ha-form/ha-form-integer.ts | 33 +++++++++-------- .../ha-selector/ha-selector-color-rgb.ts | 20 ++++------- .../ha-selector/ha-selector-number.ts | 34 ++++++++---------- src/components/input/ha-input.ts | 12 ++++++- 5 files changed, 68 insertions(+), 67 deletions(-) diff --git a/src/components/ha-form/ha-form-float.ts b/src/components/ha-form/ha-form-float.ts index f12ec6e90e..edd9a34d70 100644 --- a/src/components/ha-form/ha-form-float.ts +++ b/src/components/ha-form/ha-form-float.ts @@ -1,10 +1,10 @@ import type { PropertyValues, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; +import { css, html, LitElement, nothing } from "lit"; import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import type { LocalizeFunc } from "../../common/translations/localize"; -import "../ha-textfield"; -import type { HaTextField } from "../ha-textfield"; +import "../input/ha-input"; +import type { HaInput } from "../input/ha-input"; import type { HaFormElement, HaFormFloatData, @@ -25,7 +25,7 @@ export class HaFormFloat extends LitElement implements HaFormElement { @property({ type: Boolean }) public disabled = false; - @query("ha-textfield", true) private _input?: HaTextField; + @query("ha-input", true) private _input?: HaInput; static shadowRootOptions = { ...LitElement.shadowRootOptions, @@ -38,23 +38,25 @@ export class HaFormFloat extends LitElement implements HaFormElement { protected render(): TemplateResult { return html` - + @input=${this._handleInput} + > + ${this.schema.description?.suffix + ? html`${this.schema.description?.suffix}` + : nothing} + `; } @@ -64,9 +66,9 @@ export class HaFormFloat extends LitElement implements HaFormElement { } } - private _valueChanged(ev: Event) { - const source = ev.target as HaTextField; - const rawValue = source.value.replace(",", "."); + private _handleInput(ev: InputEvent) { + const source = ev.target as HaInput; + const rawValue = (source.value ?? "").replace(",", "."); let value: number | undefined; @@ -74,6 +76,11 @@ export class HaFormFloat extends LitElement implements HaFormElement { return; } + // Allow user to keep typing decimal places (e.g., 5.0, 5.00, 5.10) + if (rawValue.includes(".") && rawValue.endsWith("0")) { + return; + } + // Allow user to start typing a negative value if (rawValue === "-") { return; @@ -105,9 +112,6 @@ export class HaFormFloat extends LitElement implements HaFormElement { :host([own-margin]) { margin-bottom: 5px; } - ha-textfield { - display: block; - } `; } diff --git a/src/components/ha-form/ha-form-integer.ts b/src/components/ha-form/ha-form-integer.ts index b0663ae852..c079045f57 100644 --- a/src/components/ha-form/ha-form-integer.ts +++ b/src/components/ha-form/ha-form-integer.ts @@ -1,5 +1,5 @@ import type { PropertyValues, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; +import { css, html, LitElement, nothing } from "lit"; import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import type { LocalizeFunc } from "../../common/translations/localize"; @@ -7,8 +7,8 @@ import "../ha-checkbox"; import type { HaCheckbox } from "../ha-checkbox"; import "../ha-input-helper-text"; import "../ha-slider"; -import "../ha-textfield"; -import type { HaTextField } from "../ha-textfield"; +import "../input/ha-input"; +import type { HaInput } from "../input/ha-input"; import type { HaFormElement, HaFormIntegerData, @@ -29,8 +29,8 @@ export class HaFormInteger extends LitElement implements HaFormElement { @property({ type: Boolean }) public disabled = false; - @query("ha-textfield, ha-slider", true) private _input?: - | HaTextField + @query("ha-input, ha-slider", true) private _input?: + | HaInput | HTMLInputElement; private _lastValue?: HaFormIntegerData; @@ -89,28 +89,30 @@ export class HaFormInteger extends LitElement implements HaFormElement { ? html`${this.helper}` - : ""} + : nothing} `; } return html` - + > + ${this.schema.description?.suffix + ? html`${this.schema.description.suffix}` + : nothing} + `; } @@ -167,8 +169,8 @@ export class HaFormInteger extends LitElement implements HaFormElement { }); } - private _valueChanged(ev: Event) { - const source = ev.target as HaTextField | HTMLInputElement; + private _valueChanged(ev: InputEvent) { + const source = ev.target as HaInput | HTMLInputElement; const rawValue = source.value; let value: number | undefined; @@ -201,9 +203,6 @@ export class HaFormInteger extends LitElement implements HaFormElement { ha-slider { flex: 1; } - ha-textfield { - display: block; - } `; } diff --git a/src/components/ha-selector/ha-selector-color-rgb.ts b/src/components/ha-selector/ha-selector-color-rgb.ts index 40b0c1e455..c933129a01 100644 --- a/src/components/ha-selector/ha-selector-color-rgb.ts +++ b/src/components/ha-selector/ha-selector-color-rgb.ts @@ -3,13 +3,10 @@ import { customElement, property } from "lit/decorators"; import { hex2rgb, rgb2hex } from "../../common/color/convert-color"; import { fireEvent } from "../../common/dom/fire_event"; import type { ColorRGBSelector } from "../../data/selector"; -import type { HomeAssistant } from "../../types"; -import "../ha-textfield"; +import "../input/ha-input"; @customElement("ha-selector-color_rgb") export class HaColorRGBSelector extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - @property({ attribute: false }) public selector!: ColorRGBSelector; @property() public value?: string; @@ -24,16 +21,15 @@ export class HaColorRGBSelector extends LitElement { protected render() { return html` - + > `; } @@ -50,14 +46,10 @@ export class HaColorRGBSelector extends LitElement { justify-content: flex-end; align-items: center; } - ha-textfield { - --text-field-padding-top: 8px; - --text-field-padding-bottom: 8px; - --text-field-padding-start: 8px; - --text-field-padding-end: 8px; + ha-input { min-width: 75px; flex-grow: 1; - margin: 0 4px; + margin: 0 var(--ha-space-1); } `; } diff --git a/src/components/ha-selector/ha-selector-number.ts b/src/components/ha-selector/ha-selector-number.ts index a8d0eeaa3e..b4152187dd 100644 --- a/src/components/ha-selector/ha-selector-number.ts +++ b/src/components/ha-selector/ha-selector-number.ts @@ -1,19 +1,15 @@ import type { PropertyValues } from "lit"; import { css, html, LitElement, nothing } from "lit"; import { customElement, property, query } from "lit/decorators"; -import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../../common/dom/fire_event"; import type { NumberSelector } from "../../data/selector"; -import type { HomeAssistant } from "../../types"; import "../ha-input-helper-text"; import "../ha-slider"; -import "../ha-textfield"; -import type { HaTextField } from "../ha-textfield"; +import "../input/ha-input"; +import type { HaInput } from "../input/ha-input"; @customElement("ha-selector-number") export class HaNumberSelector extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - @property({ attribute: false }) public selector!: NumberSelector; @property({ type: Number }) public value?: number; @@ -31,7 +27,7 @@ export class HaNumberSelector extends LitElement { @property({ type: Boolean }) public disabled = false; - @query("ha-textfield", true) private _input?: HaTextField | HTMLInputElement; + @query("ha-input", true) private _input?: HaInput; private _valueStr = ""; @@ -99,29 +95,30 @@ export class HaNumberSelector extends LitElement { ` : nothing} - - + ${unit ? html`${unit}` : nothing} + ${!isBox && this.helper ? html`