mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-18 07:56:44 +01:00
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 <MindFreeze@users.noreply.github.com> --------- Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
import type { PropertyValues, TemplateResult } from "lit";
|
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 { customElement, property, query } from "lit/decorators";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import type { LocalizeFunc } from "../../common/translations/localize";
|
import type { LocalizeFunc } from "../../common/translations/localize";
|
||||||
import "../ha-textfield";
|
import "../input/ha-input";
|
||||||
import type { HaTextField } from "../ha-textfield";
|
import type { HaInput } from "../input/ha-input";
|
||||||
import type {
|
import type {
|
||||||
HaFormElement,
|
HaFormElement,
|
||||||
HaFormFloatData,
|
HaFormFloatData,
|
||||||
@@ -25,7 +25,7 @@ export class HaFormFloat extends LitElement implements HaFormElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public disabled = false;
|
@property({ type: Boolean }) public disabled = false;
|
||||||
|
|
||||||
@query("ha-textfield", true) private _input?: HaTextField;
|
@query("ha-input", true) private _input?: HaInput;
|
||||||
|
|
||||||
static shadowRootOptions = {
|
static shadowRootOptions = {
|
||||||
...LitElement.shadowRootOptions,
|
...LitElement.shadowRootOptions,
|
||||||
@@ -38,23 +38,25 @@ export class HaFormFloat extends LitElement implements HaFormElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-textfield
|
<ha-input
|
||||||
type="number"
|
type="number"
|
||||||
inputMode="decimal"
|
inputMode="decimal"
|
||||||
step="any"
|
step="any"
|
||||||
.label=${this.label}
|
.label=${this.label}
|
||||||
.helper=${this.helper}
|
.hint=${this.helper}
|
||||||
helperPersistent
|
|
||||||
.value=${this.data !== undefined ? this.data : ""}
|
.value=${this.data !== undefined ? this.data : ""}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.required=${this.schema.required}
|
.required=${this.schema.required}
|
||||||
.autoValidate=${this.schema.required}
|
.autoValidate=${this.schema.required}
|
||||||
.suffix=${this.schema.description?.suffix}
|
|
||||||
.validationMessage=${this.schema.required
|
.validationMessage=${this.schema.required
|
||||||
? this.localize?.("ui.common.error_required")
|
? this.localize?.("ui.common.error_required")
|
||||||
: undefined}
|
: undefined}
|
||||||
@input=${this._valueChanged}
|
@input=${this._handleInput}
|
||||||
></ha-textfield>
|
>
|
||||||
|
${this.schema.description?.suffix
|
||||||
|
? html`<span slot="end">${this.schema.description?.suffix}</span>`
|
||||||
|
: nothing}
|
||||||
|
</ha-input>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,9 +66,9 @@ export class HaFormFloat extends LitElement implements HaFormElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _valueChanged(ev: Event) {
|
private _handleInput(ev: InputEvent) {
|
||||||
const source = ev.target as HaTextField;
|
const source = ev.target as HaInput;
|
||||||
const rawValue = source.value.replace(",", ".");
|
const rawValue = (source.value ?? "").replace(",", ".");
|
||||||
|
|
||||||
let value: number | undefined;
|
let value: number | undefined;
|
||||||
|
|
||||||
@@ -74,6 +76,11 @@ export class HaFormFloat extends LitElement implements HaFormElement {
|
|||||||
return;
|
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
|
// Allow user to start typing a negative value
|
||||||
if (rawValue === "-") {
|
if (rawValue === "-") {
|
||||||
return;
|
return;
|
||||||
@@ -105,9 +112,6 @@ export class HaFormFloat extends LitElement implements HaFormElement {
|
|||||||
:host([own-margin]) {
|
:host([own-margin]) {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
ha-textfield {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { PropertyValues, TemplateResult } from "lit";
|
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 { customElement, property, query } from "lit/decorators";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import type { LocalizeFunc } from "../../common/translations/localize";
|
import type { LocalizeFunc } from "../../common/translations/localize";
|
||||||
@@ -7,8 +7,8 @@ import "../ha-checkbox";
|
|||||||
import type { HaCheckbox } from "../ha-checkbox";
|
import type { HaCheckbox } from "../ha-checkbox";
|
||||||
import "../ha-input-helper-text";
|
import "../ha-input-helper-text";
|
||||||
import "../ha-slider";
|
import "../ha-slider";
|
||||||
import "../ha-textfield";
|
import "../input/ha-input";
|
||||||
import type { HaTextField } from "../ha-textfield";
|
import type { HaInput } from "../input/ha-input";
|
||||||
import type {
|
import type {
|
||||||
HaFormElement,
|
HaFormElement,
|
||||||
HaFormIntegerData,
|
HaFormIntegerData,
|
||||||
@@ -29,8 +29,8 @@ export class HaFormInteger extends LitElement implements HaFormElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public disabled = false;
|
@property({ type: Boolean }) public disabled = false;
|
||||||
|
|
||||||
@query("ha-textfield, ha-slider", true) private _input?:
|
@query("ha-input, ha-slider", true) private _input?:
|
||||||
| HaTextField
|
| HaInput
|
||||||
| HTMLInputElement;
|
| HTMLInputElement;
|
||||||
|
|
||||||
private _lastValue?: HaFormIntegerData;
|
private _lastValue?: HaFormIntegerData;
|
||||||
@@ -89,28 +89,30 @@ export class HaFormInteger extends LitElement implements HaFormElement {
|
|||||||
? html`<ha-input-helper-text .disabled=${this.disabled}
|
? html`<ha-input-helper-text .disabled=${this.disabled}
|
||||||
>${this.helper}</ha-input-helper-text
|
>${this.helper}</ha-input-helper-text
|
||||||
>`
|
>`
|
||||||
: ""}
|
: nothing}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-textfield
|
<ha-input
|
||||||
type="number"
|
type="number"
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
.label=${this.label}
|
.label=${this.label}
|
||||||
.helper=${this.helper}
|
.hint=${this.helper}
|
||||||
helperPersistent
|
.value=${this.data !== undefined ? this.data.toString() : ""}
|
||||||
.value=${this.data !== undefined ? this.data : ""}
|
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.required=${this.schema.required}
|
.required=${this.schema.required}
|
||||||
.autoValidate=${this.schema.required}
|
.autoValidate=${this.schema.required}
|
||||||
.suffix=${this.schema.description?.suffix}
|
|
||||||
.validationMessage=${this.schema.required
|
.validationMessage=${this.schema.required
|
||||||
? this.localize?.("ui.common.error_required")
|
? this.localize?.("ui.common.error_required")
|
||||||
: undefined}
|
: undefined}
|
||||||
@input=${this._valueChanged}
|
@input=${this._valueChanged}
|
||||||
></ha-textfield>
|
>
|
||||||
|
${this.schema.description?.suffix
|
||||||
|
? html`<span slot="end">${this.schema.description.suffix}</span>`
|
||||||
|
: nothing}
|
||||||
|
</ha-input>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,8 +169,8 @@ export class HaFormInteger extends LitElement implements HaFormElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _valueChanged(ev: Event) {
|
private _valueChanged(ev: InputEvent) {
|
||||||
const source = ev.target as HaTextField | HTMLInputElement;
|
const source = ev.target as HaInput | HTMLInputElement;
|
||||||
const rawValue = source.value;
|
const rawValue = source.value;
|
||||||
|
|
||||||
let value: number | undefined;
|
let value: number | undefined;
|
||||||
@@ -201,9 +203,6 @@ export class HaFormInteger extends LitElement implements HaFormElement {
|
|||||||
ha-slider {
|
ha-slider {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
ha-textfield {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,10 @@ import { customElement, property } from "lit/decorators";
|
|||||||
import { hex2rgb, rgb2hex } from "../../common/color/convert-color";
|
import { hex2rgb, rgb2hex } from "../../common/color/convert-color";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import type { ColorRGBSelector } from "../../data/selector";
|
import type { ColorRGBSelector } from "../../data/selector";
|
||||||
import type { HomeAssistant } from "../../types";
|
import "../input/ha-input";
|
||||||
import "../ha-textfield";
|
|
||||||
|
|
||||||
@customElement("ha-selector-color_rgb")
|
@customElement("ha-selector-color_rgb")
|
||||||
export class HaColorRGBSelector extends LitElement {
|
export class HaColorRGBSelector extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public selector!: ColorRGBSelector;
|
@property({ attribute: false }) public selector!: ColorRGBSelector;
|
||||||
|
|
||||||
@property() public value?: string;
|
@property() public value?: string;
|
||||||
@@ -24,16 +21,15 @@ export class HaColorRGBSelector extends LitElement {
|
|||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
return html`
|
return html`
|
||||||
<ha-textfield
|
<ha-input
|
||||||
type="color"
|
type="color"
|
||||||
helperPersistent
|
|
||||||
.value=${this.value ? rgb2hex(this.value as any) : ""}
|
.value=${this.value ? rgb2hex(this.value as any) : ""}
|
||||||
.label=${this.label || ""}
|
.label=${this.label || ""}
|
||||||
.required=${this.required}
|
.required=${this.required}
|
||||||
.helper=${this.helper}
|
.hint=${this.helper}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
@change=${this._valueChanged}
|
@change=${this._valueChanged}
|
||||||
></ha-textfield>
|
></ha-input>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,14 +46,10 @@ export class HaColorRGBSelector extends LitElement {
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
ha-textfield {
|
ha-input {
|
||||||
--text-field-padding-top: 8px;
|
|
||||||
--text-field-padding-bottom: 8px;
|
|
||||||
--text-field-padding-start: 8px;
|
|
||||||
--text-field-padding-end: 8px;
|
|
||||||
min-width: 75px;
|
min-width: 75px;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
margin: 0 4px;
|
margin: 0 var(--ha-space-1);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
import type { PropertyValues } from "lit";
|
import type { PropertyValues } from "lit";
|
||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, query } from "lit/decorators";
|
import { customElement, property, query } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import type { NumberSelector } from "../../data/selector";
|
import type { NumberSelector } from "../../data/selector";
|
||||||
import type { HomeAssistant } from "../../types";
|
|
||||||
import "../ha-input-helper-text";
|
import "../ha-input-helper-text";
|
||||||
import "../ha-slider";
|
import "../ha-slider";
|
||||||
import "../ha-textfield";
|
import "../input/ha-input";
|
||||||
import type { HaTextField } from "../ha-textfield";
|
import type { HaInput } from "../input/ha-input";
|
||||||
|
|
||||||
@customElement("ha-selector-number")
|
@customElement("ha-selector-number")
|
||||||
export class HaNumberSelector extends LitElement {
|
export class HaNumberSelector extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public selector!: NumberSelector;
|
@property({ attribute: false }) public selector!: NumberSelector;
|
||||||
|
|
||||||
@property({ type: Number }) public value?: number;
|
@property({ type: Number }) public value?: number;
|
||||||
@@ -31,7 +27,7 @@ export class HaNumberSelector extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public disabled = false;
|
@property({ type: Boolean }) public disabled = false;
|
||||||
|
|
||||||
@query("ha-textfield", true) private _input?: HaTextField | HTMLInputElement;
|
@query("ha-input", true) private _input?: HaInput;
|
||||||
|
|
||||||
private _valueStr = "";
|
private _valueStr = "";
|
||||||
|
|
||||||
@@ -99,29 +95,30 @@ export class HaNumberSelector extends LitElement {
|
|||||||
</ha-slider>
|
</ha-slider>
|
||||||
`
|
`
|
||||||
: nothing}
|
: nothing}
|
||||||
<ha-textfield
|
<ha-input
|
||||||
.inputMode=${this.selector.number?.step === "any" ||
|
.inputMode=${this.selector.number?.step === "any" ||
|
||||||
(this.selector.number?.step ?? 1) % 1 !== 0
|
(this.selector.number?.step ?? 1) % 1 !== 0
|
||||||
? "decimal"
|
? "decimal"
|
||||||
: "numeric"}
|
: "numeric"}
|
||||||
.label=${!isBox ? undefined : this.label}
|
.label=${!isBox ? undefined : this.label}
|
||||||
.placeholder=${this.placeholder}
|
.placeholder=${this.placeholder !== undefined
|
||||||
class=${classMap({ single: isBox })}
|
? this.placeholder.toString()
|
||||||
|
: ""}
|
||||||
|
class=${isBox ? "single" : ""}
|
||||||
.min=${this.selector.number?.min}
|
.min=${this.selector.number?.min}
|
||||||
.max=${this.selector.number?.max}
|
.max=${this.selector.number?.max}
|
||||||
.value=${this._valueStr ?? ""}
|
.value=${this._valueStr ?? ""}
|
||||||
.step=${this.selector.number?.step ?? 1}
|
.step=${this.selector.number?.step ?? 1}
|
||||||
helperPersistent
|
.hint=${isBox ? this.helper : undefined}
|
||||||
.helper=${isBox ? this.helper : undefined}
|
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.required=${this.required}
|
.required=${this.required}
|
||||||
.suffix=${unit}
|
|
||||||
type="number"
|
type="number"
|
||||||
autoValidate
|
autoValidate
|
||||||
?no-spinner=${!isBox}
|
.withoutSpinButtons=${!isBox}
|
||||||
@input=${this._handleInputChange}
|
@input=${this._handleInputChange}
|
||||||
>
|
>
|
||||||
</ha-textfield>
|
${unit ? html`<span slot="end">${unit}</span>` : nothing}
|
||||||
|
</ha-input>
|
||||||
</div>
|
</div>
|
||||||
${!isBox && this.helper
|
${!isBox && this.helper
|
||||||
? html`<ha-input-helper-text .disabled=${this.disabled}
|
? html`<ha-input-helper-text .disabled=${this.disabled}
|
||||||
@@ -166,11 +163,10 @@ export class HaNumberSelector extends LitElement {
|
|||||||
margin-inline-end: 16px;
|
margin-inline-end: 16px;
|
||||||
margin-inline-start: 0;
|
margin-inline-start: 0;
|
||||||
}
|
}
|
||||||
ha-textfield {
|
ha-input::part(wa-input) {
|
||||||
--ha-textfield-input-width: 40px;
|
width: 40px;
|
||||||
}
|
}
|
||||||
.single {
|
ha-input.single {
|
||||||
--ha-textfield-input-width: unset;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export type InputType =
|
|||||||
| "tel"
|
| "tel"
|
||||||
| "text"
|
| "text"
|
||||||
| "time"
|
| "time"
|
||||||
|
| "color"
|
||||||
| "url";
|
| "url";
|
||||||
|
|
||||||
@customElement("ha-input")
|
@customElement("ha-input")
|
||||||
@@ -296,7 +297,9 @@ export class HaInput extends LitElement {
|
|||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
class=${classMap({
|
class=${classMap({
|
||||||
invalid: this.invalid || this._invalid,
|
invalid: this.invalid || this._invalid,
|
||||||
"label-raised": this.value || (this.label && this.placeholder),
|
"label-raised":
|
||||||
|
(this.value !== undefined && this.value !== "") ||
|
||||||
|
(this.label && this.placeholder),
|
||||||
"no-label": !this.label,
|
"no-label": !this.label,
|
||||||
"hint-hidden":
|
"hint-hidden":
|
||||||
!this.hint &&
|
!this.hint &&
|
||||||
@@ -512,6 +515,13 @@ export class HaInput extends LitElement {
|
|||||||
}
|
}
|
||||||
:host([type="color"]) wa-input::part(input) {
|
:host([type="color"]) wa-input::part(input) {
|
||||||
padding-top: var(--ha-space-6);
|
padding-top: var(--ha-space-6);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
:host([type="color"]) wa-input.no-label::part(input) {
|
||||||
|
padding: var(--ha-space-2);
|
||||||
|
}
|
||||||
|
:host([type="color"]) wa-input.no-label::part(base) {
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
wa-input::part(input)::placeholder {
|
wa-input::part(input)::placeholder {
|
||||||
color: var(--ha-color-neutral-60);
|
color: var(--ha-color-neutral-60);
|
||||||
|
|||||||
Reference in New Issue
Block a user