diff --git a/gallery/src/pages/components/ha-selector.ts b/gallery/src/pages/components/ha-selector.ts index 15482b68d0..972c7d7f26 100644 --- a/gallery/src/pages/components/ha-selector.ts +++ b/gallery/src/pages/components/ha-selector.ts @@ -261,6 +261,8 @@ class DemoHaSelector extends LitElement implements ProvideHassElement { @state() private _required = false; + @state() private _helper = false; + @state() private _label = true; private data = SCHEMAS.map(() => ({})); @@ -418,6 +420,13 @@ class DemoHaSelector extends LitElement implements ProvideHassElement { @change=${this._handleOptionChange} > + + + ${SCHEMAS.map((info, idx) => { const data = this.data[idx]; @@ -446,6 +455,7 @@ class DemoHaSelector extends LitElement implements ProvideHassElement { .disabled=${this._disabled} .required=${this._required} @value-changed=${valueChanged} + .helper=${this._helper ? "Helper text" : undefined} > ` @@ -466,7 +476,8 @@ class DemoHaSelector extends LitElement implements ProvideHassElement { width: 60; } .options { - padding: 16px 48px; + max-width: 800px; + margin: 16px auto; } .options ha-formfield { margin-right: 16px; diff --git a/src/components/device/ha-device-picker.ts b/src/components/device/ha-device-picker.ts index ea62482637..9ff64d812f 100644 --- a/src/components/device/ha-device-picker.ts +++ b/src/components/device/ha-device-picker.ts @@ -52,6 +52,8 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { @property() public value?: string; + @property() public helper?: string; + @property() public devices?: DeviceRegistryEntry[]; @property() public areas?: AreaRegistryEntry[]; @@ -269,6 +271,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { ? this.hass.localize("ui.components.device-picker.device") : this.label} .value=${this._value} + .helper=${this.helper} .renderer=${rowRenderer} .disabled=${this.disabled} .required=${this.required} diff --git a/src/components/device/ha-devices-picker.ts b/src/components/device/ha-devices-picker.ts index 5b2e0245b9..688467c2a8 100644 --- a/src/components/device/ha-devices-picker.ts +++ b/src/components/device/ha-devices-picker.ts @@ -11,6 +11,8 @@ class HaDevicesPicker extends LitElement { @property() public value?: string[]; + @property() public helper?: string; + @property({ type: Boolean }) public required?: boolean; /** @@ -64,6 +66,7 @@ class HaDevicesPicker extends LitElement {
diff --git a/src/components/entity/ha-entity-attribute-picker.ts b/src/components/entity/ha-entity-attribute-picker.ts index 49bfd1db33..3a73ad3fcb 100644 --- a/src/components/entity/ha-entity-attribute-picker.ts +++ b/src/components/entity/ha-entity-attribute-picker.ts @@ -28,6 +28,8 @@ class HaEntityAttributePicker extends LitElement { @property() public value?: string; + @property() public helper?: string; + @property({ type: Boolean }) private _opened = false; @query("ha-combo-box", true) private _comboBox!: HaComboBox; @@ -64,6 +66,7 @@ class HaEntityAttributePicker extends LitElement { )} .disabled=${this.disabled || !this.entityId} .required=${this.required} + .helper=${this.helper} .allowCustomValue=${this.allowCustomValue} item-value-path="value" item-label-path="label" diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts index c8f288ad70..7f9c8d3d80 100644 --- a/src/components/entity/ha-entity-picker.ts +++ b/src/components/entity/ha-entity-picker.ts @@ -48,6 +48,8 @@ export class HaEntityPicker extends LitElement { @property() public value?: string; + @property() public helper?: string; + /** * Show entities from specific domains. * @type {Array} @@ -304,6 +306,7 @@ export class HaEntityPicker extends LitElement { .label=${this.label === undefined ? this.hass.localize("ui.components.entity.entity-picker.entity") : this.label} + .helper=${this.helper} .allowCustomValue=${this.allowCustomEntity} .filteredItems=${this._states} .renderer=${rowRenderer} diff --git a/src/components/ha-addon-picker.ts b/src/components/ha-addon-picker.ts index 7a7abf13b1..d2b413cace 100644 --- a/src/components/ha-addon-picker.ts +++ b/src/components/ha-addon-picker.ts @@ -29,6 +29,8 @@ class HaAddonPicker extends LitElement { @property() public value = ""; + @property() public helper?: string; + @state() private _addons?: HassioAddonInfo[]; @property({ type: Boolean }) public disabled = false; @@ -62,6 +64,7 @@ class HaAddonPicker extends LitElement { .value=${this._value} .required=${this.required} .disabled=${this.disabled} + .helper=${this.helper} .renderer=${rowRenderer} .items=${this._addons} item-value-path="slug" diff --git a/src/components/ha-area-picker.ts b/src/components/ha-area-picker.ts index b841575b67..2192bd931c 100644 --- a/src/components/ha-area-picker.ts +++ b/src/components/ha-area-picker.ts @@ -49,6 +49,8 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) { @property() public value?: string; + @property() public helper?: string; + @property() public placeholder?: string; @property({ type: Boolean, attribute: "no-add" }) @@ -312,6 +314,7 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) { return html` PM `}
- ${this.helper ? html`
${this.helper}
` : ""} + ${this.helper + ? html`${this.helper}` + : ""} `; } @@ -350,13 +353,6 @@ export class HaBaseTimeInput extends LitElement { color: var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87)); padding-left: 4px; } - - .helper { - color: var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6)); - font-size: 0.75rem; - padding-left: 16px; - padding-right: 16px; - } `; } diff --git a/src/components/ha-combo-box.ts b/src/components/ha-combo-box.ts index c1bc266ed9..c0166ddfa8 100644 --- a/src/components/ha-combo-box.ts +++ b/src/components/ha-combo-box.ts @@ -64,6 +64,8 @@ export class HaComboBox extends LitElement { @property() public validationMessage?: string; + @property() public helper?: string; + @property({ attribute: "error-message" }) public errorMessage?: string; @property({ type: Boolean }) public invalid?: boolean; @@ -147,6 +149,8 @@ export class HaComboBox extends LitElement { .suffix=${html`
`} .icon=${this.icon} .invalid=${this.invalid} + .helper=${this.helper} + helperPersistent > diff --git a/src/components/ha-date-input.ts b/src/components/ha-date-input.ts index 0963b1fd02..c776519ceb 100644 --- a/src/components/ha-date-input.ts +++ b/src/components/ha-date-input.ts @@ -39,11 +39,15 @@ export class HaDateInput extends LitElement { @property() public label?: string; + @property() public helper?: string; + render() { return html``; + } + + static styles = css` + :host { + display: block; + color: var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6)); + font-size: 0.75rem; + padding-left: 16px; + padding-right: 16px; + } + `; +} + +declare global { + interface HTMLElementTagNameMap { + "ha-input-helper-text": InputHelperText; + } +} diff --git a/src/components/ha-labeled-slider.js b/src/components/ha-labeled-slider.js index af7134ab13..00d1b1848f 100644 --- a/src/components/ha-labeled-slider.js +++ b/src/components/ha-labeled-slider.js @@ -46,6 +46,9 @@ class HaLabeledSlider extends PolymerElement { value="{{value}}" > + `; } @@ -62,6 +65,7 @@ class HaLabeledSlider extends PolymerElement { max: Number, pin: Boolean, step: Number, + helper: String, extra: { type: Boolean, diff --git a/src/components/ha-selector/ha-selector-addon.ts b/src/components/ha-selector/ha-selector-addon.ts index acabb24cf5..91aee42777 100644 --- a/src/components/ha-selector/ha-selector-addon.ts +++ b/src/components/ha-selector/ha-selector-addon.ts @@ -14,6 +14,8 @@ export class HaAddonSelector extends LitElement { @property() public label?: string; + @property() public helper?: string; + @property({ type: Boolean }) public disabled = false; @property({ type: Boolean }) public required = true; @@ -23,6 +25,7 @@ export class HaAddonSelector extends LitElement { .hass=${this.hass} .value=${this.value} .label=${this.label} + .helper=${this.helper} .disabled=${this.disabled} .required=${this.required} allow-custom-entity diff --git a/src/components/ha-selector/ha-selector-area.ts b/src/components/ha-selector/ha-selector-area.ts index 8aaada7e23..f922d8d0c6 100644 --- a/src/components/ha-selector/ha-selector-area.ts +++ b/src/components/ha-selector/ha-selector-area.ts @@ -18,6 +18,8 @@ export class HaAreaSelector extends LitElement { @property() public label?: string; + @property() public helper?: string; + @state() public _configEntries?: ConfigEntry[]; @property({ type: Boolean }) public disabled = false; @@ -47,6 +49,7 @@ export class HaAreaSelector extends LitElement { .hass=${this.hass} .value=${this.value} .label=${this.label} + .helper=${this.helper} no-add .deviceFilter=${this._filterDevices} .entityFilter=${this._filterEntities} @@ -66,6 +69,7 @@ export class HaAreaSelector extends LitElement { - - `; + return html` + + + + ${this.helper + ? html`${this.helper}` + : ""} + `; } private _handleChange(ev) { @@ -35,12 +43,10 @@ export class HaBooleanSelector extends LitElement { static get styles(): CSSResultGroup { return css` - :host { - height: 56px; - display: flex; - } ha-formfield { - width: 100%; + display: flex; + height: 56px; + align-items: center; --mdc-typography-body2-font-size: 1em; } `; diff --git a/src/components/ha-selector/ha-selector-color-rgb.ts b/src/components/ha-selector/ha-selector-color-rgb.ts index 780d83c832..8597fa783e 100644 --- a/src/components/ha-selector/ha-selector-color-rgb.ts +++ b/src/components/ha-selector/ha-selector-color-rgb.ts @@ -16,6 +16,8 @@ export class HaColorRGBSelector extends LitElement { @property() public label?: string; + @property() public helper?: string; + @property({ type: Boolean, reflect: true }) public disabled = false; @property({ type: Boolean }) public required = true; @@ -24,9 +26,11 @@ export class HaColorRGBSelector extends LitElement { return html` diff --git a/src/components/ha-selector/ha-selector-color-temp.ts b/src/components/ha-selector/ha-selector-color-temp.ts index 67ac8abcc7..c3cbb5ffe8 100644 --- a/src/components/ha-selector/ha-selector-color-temp.ts +++ b/src/components/ha-selector/ha-selector-color-temp.ts @@ -15,6 +15,8 @@ export class HaColorTempSelector extends LitElement { @property() public label?: string; + @property() public helper?: string; + @property({ type: Boolean, reflect: true }) public disabled = false; @property({ type: Boolean }) public required = true; @@ -29,6 +31,7 @@ export class HaColorTempSelector extends LitElement { .max=${this.selector.color_temp.max_mireds ?? 500} .value=${this.value} .disabled=${this.disabled} + .helper=${this.helper} .required=${this.required} @change=${this._valueChanged} > diff --git a/src/components/ha-selector/ha-selector-date.ts b/src/components/ha-selector/ha-selector-date.ts index 47fa5b7d91..cfde72537e 100644 --- a/src/components/ha-selector/ha-selector-date.ts +++ b/src/components/ha-selector/ha-selector-date.ts @@ -14,6 +14,8 @@ export class HaDateSelector extends LitElement { @property() public label?: string; + @property() public helper?: string; + @property({ type: Boolean, reflect: true }) public disabled = false; @property({ type: Boolean }) public required = true; @@ -26,6 +28,7 @@ export class HaDateSelector extends LitElement { .disabled=${this.disabled} .value=${this.value} .required=${this.required} + .helper=${this.helper} > `; diff --git a/src/components/ha-selector/ha-selector-datetime.ts b/src/components/ha-selector/ha-selector-datetime.ts index c8d1dab2d3..cdb15ccacc 100644 --- a/src/components/ha-selector/ha-selector-datetime.ts +++ b/src/components/ha-selector/ha-selector-datetime.ts @@ -6,6 +6,7 @@ import type { HomeAssistant } from "../../types"; import "../ha-date-input"; import type { HaDateInput } from "../ha-date-input"; import "../ha-time-input"; +import "../ha-input-helper-text"; import type { HaTimeInput } from "../ha-time-input"; @customElement("ha-selector-datetime") @@ -18,6 +19,8 @@ export class HaDateTimeSelector extends LitElement { @property() public label?: string; + @property() public helper?: string; + @property({ type: Boolean, reflect: true }) public disabled = false; @property({ type: Boolean }) public required = true; @@ -30,23 +33,28 @@ export class HaDateTimeSelector extends LitElement { const values = this.value?.split(" "); return html` - - - +
+ + + +
+ ${this.helper + ? html`${this.helper}` + : ""} `; } @@ -58,7 +66,7 @@ export class HaDateTimeSelector extends LitElement { } static styles = css` - :host { + .input { display: flex; align-items: center; flex-direction: row; diff --git a/src/components/ha-selector/ha-selector-device.ts b/src/components/ha-selector/ha-selector-device.ts index efb5dee013..b6358bf284 100644 --- a/src/components/ha-selector/ha-selector-device.ts +++ b/src/components/ha-selector/ha-selector-device.ts @@ -17,6 +17,8 @@ export class HaDeviceSelector extends LitElement { @property() public label?: string; + @property() public helper?: string; + @state() public _configEntries?: ConfigEntry[]; @property({ type: Boolean }) public disabled = false; @@ -43,6 +45,7 @@ export class HaDeviceSelector extends LitElement { .hass=${this.hass} .value=${this.value} .label=${this.label} + .helper=${this.helper} .deviceFilter=${this._filterDevices} .includeDeviceClasses=${this.selector.device.entity?.device_class ? [this.selector.device.entity.device_class] @@ -62,6 +65,7 @@ export class HaDeviceSelector extends LitElement { + ${!isBox + ? html` ` + : ""} + + + + ${!isBox && this.helper + ? html`${this.helper}` : ""} - - `; + `; } private get _value() { @@ -92,7 +103,7 @@ export class HaNumberSelector extends LitElement { static get styles(): CSSResultGroup { return css` - :host { + .input { display: flex; justify-content: space-between; align-items: center; diff --git a/src/components/ha-selector/ha-selector-select.ts b/src/components/ha-selector/ha-selector-select.ts index 2f79979e90..85eaefd610 100644 --- a/src/components/ha-selector/ha-selector-select.ts +++ b/src/components/ha-selector/ha-selector-select.ts @@ -58,6 +58,7 @@ export class HaSelectSelector extends LitElement { ` )} + ${this._renderHelper()} `; } @@ -76,6 +77,7 @@ export class HaSelectSelector extends LitElement { ` )} + ${this._renderHelper()} `; } @@ -107,6 +109,7 @@ export class HaSelectSelector extends LitElement { item-label-path="label" .hass=${this.hass} .label=${this.label} + .helper=${this.helper} .disabled=${this.disabled} .required=${this.required && !value.length} .value=${this._filter} @@ -131,6 +134,7 @@ export class HaSelectSelector extends LitElement { item-label-path="label" .hass=${this.hass} .label=${this.label} + .helper=${this.helper} .disabled=${this.disabled} .required=${this.required} .items=${options} @@ -161,6 +165,12 @@ export class HaSelectSelector extends LitElement { `; } + private _renderHelper() { + return this.helper + ? html`${this.helper}` + : ""; + } + private get _mode(): "list" | "dropdown" { return ( this.selector.select.mode || diff --git a/src/components/ha-selector/ha-selector-target.ts b/src/components/ha-selector/ha-selector-target.ts index cf25317cce..4720598a77 100644 --- a/src/components/ha-selector/ha-selector-target.ts +++ b/src/components/ha-selector/ha-selector-target.ts @@ -26,6 +26,8 @@ export class HaTargetSelector extends SubscribeMixin(LitElement) { @property() public label?: string; + @property() public helper?: string; + @state() private _entityPlaformLookup?: Record; @state() private _configEntries?: ConfigEntry[]; @@ -64,6 +66,7 @@ export class HaTargetSelector extends SubscribeMixin(LitElement) { return html` diff --git a/src/components/ha-target-picker.ts b/src/components/ha-target-picker.ts index 85fb984a59..b1182779bb 100644 --- a/src/components/ha-target-picker.ts +++ b/src/components/ha-target-picker.ts @@ -43,6 +43,7 @@ import type { HaEntityPickerEntityFilterFunc } from "./entity/ha-entity-picker"; import "./ha-area-picker"; import "./ha-icon-button"; import "./ha-svg-icon"; +import "./ha-input-helper-text"; @customElement("ha-target-picker") export class HaTargetPicker extends SubscribeMixin(LitElement) { @@ -52,6 +53,8 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { @property() public label?: string; + @property() public helper?: string; + /** * Show only targets with entities from specific domains. * @type {Array} @@ -213,7 +216,11 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { - `; + + + ${this.helper + ? html`${this.helper}` + : ""} `; } private async _showPicker(ev) { diff --git a/src/components/ha-time-input.ts b/src/components/ha-time-input.ts index 2bf5659841..eadbc744ce 100644 --- a/src/components/ha-time-input.ts +++ b/src/components/ha-time-input.ts @@ -14,6 +14,8 @@ export class HaTimeInput extends LitElement { @property() public label?: string; + @property() public helper?: string; + @property({ type: Boolean }) public disabled = false; @property({ type: Boolean }) public required = false; @@ -46,6 +48,7 @@ export class HaTimeInput extends LitElement { @value-changed=${this._timeChanged} .enableSecond=${this.enableSecond} .required=${this.required} + .helper=${this.helper} > `; } diff --git a/src/components/map/ha-locations-editor.ts b/src/components/map/ha-locations-editor.ts index d21a7185ac..2dcc446099 100644 --- a/src/components/map/ha-locations-editor.ts +++ b/src/components/map/ha-locations-editor.ts @@ -21,6 +21,7 @@ import type { LeafletModuleType } from "../../common/dom/setup-leaflet-map"; import type { HomeAssistant } from "../../types"; import "./ha-map"; import type { HaMap } from "./ha-map"; +import "../ha-input-helper-text"; declare global { // for fire event @@ -50,6 +51,8 @@ export class HaLocationsEditor extends LitElement { @property({ attribute: false }) public locations?: MarkerLocation[]; + @property() public helper?: string; + @property({ type: Boolean }) public autoFit = false; @property({ type: Number }) public zoom = 16; @@ -102,13 +105,18 @@ export class HaLocationsEditor extends LitElement { } protected render(): TemplateResult { - return html``; + return html` + + ${this.helper + ? html`${this.helper}` + : ""} + `; } private _getLayers = memoizeOne( @@ -287,13 +295,10 @@ export class HaLocationsEditor extends LitElement { static get styles(): CSSResultGroup { return css` - :host { + ha-map { display: block; height: 300px; } - ha-map { - height: 100%; - } `; } }