diff --git a/src/components/date-picker/date-range-picker.ts b/src/components/date-picker/date-range-picker.ts index 677660c3f3..3152615d31 100644 --- a/src/components/date-picker/date-range-picker.ts +++ b/src/components/date-picker/date-range-picker.ts @@ -4,7 +4,7 @@ import type { ActionDetail } from "@material/mwc-list"; import { mdiCalendarToday } from "@mdi/js"; import "cally"; import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; +import { customElement, property, queryAll, state } from "lit/decorators"; import { firstWeekdayIndex } from "../../common/datetime/first_weekday"; import { formatCallyDateRange, @@ -29,6 +29,7 @@ import "../ha-list-item"; import "../ha-time-input"; import type { DateRangePickerRanges } from "./ha-date-range-picker"; import { datePickerStyles, dateRangePickerStyles } from "./styles"; +import type { HaTimeInput } from "../ha-time-input"; @customElement("date-range-picker") export class DateRangePicker extends LitElement { @@ -69,6 +70,8 @@ export class DateRangePicker extends LitElement { to: { hours: 23, minutes: 59 }, }; + @queryAll("ha-time-input") private _timeInputs?: NodeListOf; + public connectedCallback() { super.connectedCallback(); @@ -153,6 +156,7 @@ export class DateRangePicker extends LitElement { )} id="from" placeholder-labels + auto-validate > ` @@ -200,6 +205,14 @@ export class DateRangePicker extends LitElement { let endDate = new Date(`${dates[1]}T23:59:00`); if (this.timePicker) { + const timeInputs = this._timeInputs; + if ( + timeInputs && + ![...timeInputs].every((input) => input.reportValidity()) + ) { + // If we have time inputs, and they don't all report valid, don't save + return; + } startDate.setHours(this._timeValue.from.hours); startDate.setMinutes(this._timeValue.from.minutes); endDate.setHours(this._timeValue.to.hours); @@ -281,7 +294,8 @@ export class DateRangePicker extends LitElement { private _handleChangeTime(ev: ValueChangedEvent) { ev.stopPropagation(); const time = ev.detail.value; - const type = (ev.target as HaBaseTimeInput).id; + const target = ev.target as HaBaseTimeInput; + const type = target.id; if (time) { if (!this._timeValue) { this._timeValue = { diff --git a/src/components/ha-base-time-input.ts b/src/components/ha-base-time-input.ts index e0aeb75142..3ab107c2e4 100644 --- a/src/components/ha-base-time-input.ts +++ b/src/components/ha-base-time-input.ts @@ -137,7 +137,7 @@ export class HaBaseTimeInput extends LitElement { @property({ attribute: "placeholder-labels", type: Boolean }) public placeholderLabels = false; - @queryAll("ha-input") private _inputs?: HaInput[]; + @queryAll("ha-input") private _inputs?: NodeListOf; static shadowRootOptions = { ...LitElement.shadowRootOptions, @@ -145,7 +145,9 @@ export class HaBaseTimeInput extends LitElement { }; public reportValidity(): boolean { - return this._inputs?.every((input) => input.reportValidity()) ?? true; + const inputs = this._inputs; + if (!inputs) return true; + return [...inputs].every((input) => input.reportValidity()); } protected render(): TemplateResult { diff --git a/src/components/ha-time-input.ts b/src/components/ha-time-input.ts index 79281ccd3a..090a6c2dbb 100644 --- a/src/components/ha-time-input.ts +++ b/src/components/ha-time-input.ts @@ -21,6 +21,8 @@ export class HaTimeInput extends LitElement { @property({ type: Boolean }) public required = false; + @property({ attribute: "auto-validate", type: Boolean }) autoValidate = false; + @property({ type: Boolean, attribute: "enable-second" }) public enableSecond = false; @@ -71,6 +73,7 @@ export class HaTimeInput extends LitElement { .clearable=${this.clearable && this.value !== undefined} .helper=${this.helper} .placeholderLabels=${this.placeholderLabels} + .autoValidate=${this.autoValidate} day-label="dd" hour-label="hh" min-label="mm" @@ -86,6 +89,7 @@ export class HaTimeInput extends LitElement { const useAMPM = useAmPm(this.locale); let value: string | undefined; + let updateHours = 0; // An undefined eventValue means the time selector is being cleared, // the `value` variable will (intentionally) be left undefined. @@ -97,6 +101,8 @@ export class HaTimeInput extends LitElement { ) { let hours = eventValue.hours || 0; if (eventValue && useAMPM) { + updateHours = + hours >= 12 && hours < 24 ? hours - 12 : hours === 0 ? 12 : 0; if (eventValue.amPm === "PM" && hours < 12) { hours += 12; } @@ -115,6 +121,17 @@ export class HaTimeInput extends LitElement { }`; } + if (updateHours) { + // If the user entered a 24hr time in a 12hr input, we need to refresh the + // input to ensure it resets back to the 12hr equivalent. + this.updateComplete.then(() => { + const input = this._input; + if (input) { + input.hours = updateHours; + } + }); + } + if (value === this.value) { return; }