mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-17 15:45:43 +01:00
* Fix base time inputs reportValidity() function The queryAll selector returns a NodeList not not an array. Need to spread it to an array before we can use every(). * Validate the date range picker time inputs Enable auto validation to get the nice red underline on invalid values, and then check validity before accepting the input. * Fix automatic 24hr value conversion in AM/PM format When using AM/PM, entering a 24 hour value will automatically convert the first time. For example 15 will become 3. However if you then enter 15 again it will stay as 15 and not update. To fix this, make sure we trigger an update of the input field once the current update cycle is complete. * Validate time inputs on save not value update In the value changed callback, the update 24->12hr input correction will not have been updated and therefore they will report invalid.
152 lines
4.4 KiB
TypeScript
152 lines
4.4 KiB
TypeScript
import { html, LitElement } from "lit";
|
|
import { customElement, property, query } from "lit/decorators";
|
|
import { useAmPm } from "../common/datetime/use_am_pm";
|
|
import { fireEvent } from "../common/dom/fire_event";
|
|
import type { FrontendLocaleData } from "../data/translation";
|
|
import type { ValueChangedEvent } from "../types";
|
|
import "./ha-base-time-input";
|
|
import type { HaBaseTimeInput, TimeChangedEvent } from "./ha-base-time-input";
|
|
|
|
@customElement("ha-time-input")
|
|
export class HaTimeInput extends LitElement {
|
|
@property({ attribute: false }) public locale!: FrontendLocaleData;
|
|
|
|
@property() public value?: string;
|
|
|
|
@property() public label?: string;
|
|
|
|
@property() public helper?: string;
|
|
|
|
@property({ type: Boolean }) public disabled = false;
|
|
|
|
@property({ type: Boolean }) public required = false;
|
|
|
|
@property({ attribute: "auto-validate", type: Boolean }) autoValidate = false;
|
|
|
|
@property({ type: Boolean, attribute: "enable-second" })
|
|
public enableSecond = false;
|
|
|
|
@property({ type: Boolean, reflect: true }) public clearable?: boolean;
|
|
|
|
@property({ attribute: "placeholder-labels", type: Boolean })
|
|
public placeholderLabels = false;
|
|
|
|
@query("ha-base-time-input") private _input?: HaBaseTimeInput;
|
|
|
|
public reportValidity(): boolean {
|
|
return this._input?.reportValidity() ?? true;
|
|
}
|
|
|
|
protected render() {
|
|
const useAMPM = useAmPm(this.locale);
|
|
|
|
let hours = NaN;
|
|
let minutes = NaN;
|
|
let seconds = NaN;
|
|
let numberHours = 0;
|
|
if (this.value) {
|
|
const parts = this.value?.split(":") || [];
|
|
minutes = parts[1] ? Number(parts[1]) : 0;
|
|
seconds = parts[2] ? Number(parts[2]) : 0;
|
|
hours = parts[0] ? Number(parts[0]) : 0;
|
|
numberHours = hours;
|
|
if (numberHours && useAMPM && numberHours > 12 && numberHours < 24) {
|
|
hours = numberHours - 12;
|
|
}
|
|
if (useAMPM && numberHours === 0) {
|
|
hours = 12;
|
|
}
|
|
}
|
|
|
|
return html`
|
|
<ha-base-time-input
|
|
.label=${this.label}
|
|
.hours=${hours}
|
|
.minutes=${minutes}
|
|
.seconds=${seconds}
|
|
.format=${useAMPM ? 12 : 24}
|
|
.amPm=${useAMPM && numberHours >= 12 ? "PM" : "AM"}
|
|
.disabled=${this.disabled}
|
|
@value-changed=${this._timeChanged}
|
|
.enableSecond=${this.enableSecond}
|
|
.required=${this.required}
|
|
.clearable=${this.clearable && this.value !== undefined}
|
|
.helper=${this.helper}
|
|
.placeholderLabels=${this.placeholderLabels}
|
|
.autoValidate=${this.autoValidate}
|
|
day-label="dd"
|
|
hour-label="hh"
|
|
min-label="mm"
|
|
sec-label="ss"
|
|
ms-label="ms"
|
|
></ha-base-time-input>
|
|
`;
|
|
}
|
|
|
|
private _timeChanged(ev: ValueChangedEvent<TimeChangedEvent | undefined>) {
|
|
ev.stopPropagation();
|
|
const eventValue = ev.detail.value;
|
|
|
|
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.
|
|
if (
|
|
eventValue !== undefined &&
|
|
(!isNaN(eventValue.hours) ||
|
|
!isNaN(eventValue.minutes) ||
|
|
!isNaN(eventValue.seconds))
|
|
) {
|
|
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;
|
|
}
|
|
if (eventValue.amPm === "AM" && hours === 12) {
|
|
hours = 0;
|
|
}
|
|
}
|
|
value = `${hours.toString().padStart(2, "0")}:${
|
|
eventValue.minutes
|
|
? eventValue.minutes.toString().padStart(2, "0")
|
|
: "00"
|
|
}:${
|
|
eventValue.seconds
|
|
? eventValue.seconds.toString().padStart(2, "0")
|
|
: "00"
|
|
}`;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
this.value = value;
|
|
fireEvent(this, "change");
|
|
fireEvent(this, "value-changed", {
|
|
value,
|
|
});
|
|
}
|
|
}
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
"ha-time-input": HaTimeInput;
|
|
}
|
|
}
|