This commit is contained in:
Aidan Timson
2025-08-29 15:51:03 +01:00
parent bf351d67e9
commit 5b8c5375b4
2 changed files with 254 additions and 0 deletions

View File

@@ -0,0 +1,191 @@
import type { PropertyValues } from "lit";
import { html, LitElement, nothing } from "lit";
import { customElement, property, state } 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 "./ha-base-time-input";
import "./ha-numeric-arrow-input";
import "./ha-button";
@customElement("ha-time-picker")
export class HaTimePicker extends LitElement {
@property({ attribute: false }) public locale!: FrontendLocaleData;
@property() public value?: string;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = false;
@property({ type: Boolean, attribute: "enable-second" })
public enableSecond = false;
@state() private _hours = 0;
@state() private _minutes = 0;
@state() private _seconds = 0;
@state() private _useAmPm = false;
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
this._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 &&
this._useAmPm &&
numberHours > 12 &&
numberHours < 24
) {
hours = numberHours - 12;
}
if (this._useAmPm && numberHours === 0) {
hours = 12;
}
}
this._hours = hours;
this._minutes = minutes;
this._seconds = seconds;
}
protected render() {
return html`<div class="container">
<ha-numeric-arrow-input
.disabled=${this.disabled}
.required=${this.required}
.min=${this._useAmPm ? 1 : 0}
.max=${this._useAmPm ? 12 : 23}
.step=${1}
.value=${this._hours}
@value-changed=${this._hoursChanged}
></ha-numeric-arrow-input>
<ha-numeric-arrow-input
.disabled=${this.disabled}
.required=${this.required}
.min=${0}
.max=${59}
.step=${1}
.value=${this._minutes}
@value-changed=${this._minutesChanged}
></ha-numeric-arrow-input>
${this.enableSecond
? html`
<ha-numeric-arrow-input
.disabled=${this.disabled}
.required=${this.required}
.min=${0}
.max=${59}
.step=${1}
.value=${this._seconds}
@value-changed=${this._secondsChanged}
></ha-numeric-arrow-input>
`
: nothing}
${this._useAmPm
? html`
<ha-button @click=${this._toggleAmPm}>
${this._hours > 12 ? "PM" : "AM"}
</ha-button>
`
: nothing}
</div>`;
}
protected updated(changedProperties: PropertyValues) {
super.updated(changedProperties);
if (changedProperties.has("value")) {
this._timeUpdated();
}
if (changedProperties.has("_hours")) {
this._timeUpdated();
}
if (changedProperties.has("_minutes")) {
this._timeUpdated();
}
if (changedProperties.has("_seconds")) {
this._timeUpdated();
}
if (changedProperties.has("_useAmPm")) {
this._timeUpdated();
}
}
private _hoursChanged(ev: CustomEvent<{ value?: number }>) {
const value = ev.detail.value;
if (value) {
if (this._useAmPm) {
if (value > 12) {
this._hours = value - 12;
} else if (value === 0) {
this._hours = 12;
} else {
this._hours = value;
}
} else {
this._hours = value;
}
}
}
private _minutesChanged(ev: CustomEvent<{ value?: number }>) {
const value = ev.detail.value;
if (value) {
this._minutes = value;
}
}
private _secondsChanged(ev: CustomEvent<{ value?: number }>) {
const value = ev.detail.value;
if (value) {
this._seconds = value;
}
}
private _toggleAmPm() {
this._hours = this._hours > 12 ? this._hours - 12 : this._hours + 12;
}
private _timeUpdated() {
const timeParts = [
this._hours.toString().padStart(2, "0"),
this._minutes.toString().padStart(2, "0"),
this._seconds.toString().padStart(2, "0"),
];
if (this._useAmPm) {
timeParts.push(this._hours > 12 ? "PM" : "AM");
}
const time = timeParts.join(":");
if (time === this.value) {
return;
}
this.value = time;
fireEvent(this, "change");
fireEvent(this, "value-changed", { value: time });
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-time-picker": HaTimePicker;
}
}