Skip to content

Commit

Permalink
New date picker (#11555)
Browse files Browse the repository at this point in the history
  • Loading branch information
bramkragten committed Feb 5, 2022
1 parent 9b97faa commit 45e6ec1
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 144 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,13 @@
"@polymer/polymer": "3.4.1",
"@thomasloven/round-slider": "0.5.4",
"@vaadin/combo-box": "^22.0.4",
"@vaadin/date-picker": "^22.0.4",
"@vaadin/vaadin-themable-mixin": "^22.0.4",
"@vibrant/color": "^3.2.1-alpha.1",
"@vibrant/core": "^3.2.1-alpha.1",
"@vibrant/quantizer-mmcq": "^3.2.1-alpha.1",
"@vue/web-component-wrapper": "^1.2.0",
"@webcomponents/webcomponentsjs": "^2.2.10",
"app-datepicker": "^5.0.1",
"chart.js": "^3.3.2",
"comlink": "^4.3.1",
"core-js": "^3.15.2",
Expand Down
153 changes: 47 additions & 106 deletions src/components/ha-date-input.ts
Original file line number Diff line number Diff line change
@@ -1,133 +1,74 @@
import { mdiCalendar } from "@mdi/js";
import "@polymer/paper-input/paper-input";
import "@vaadin/date-picker/theme/material/vaadin-date-picker-light";
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
import { customElement, property, query } from "lit/decorators";
import { css, CSSResultGroup, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { formatDateNumeric } from "../common/datetime/format_date";
import { fireEvent } from "../common/dom/fire_event";
import { HomeAssistant } from "../types";
import "./ha-svg-icon";

const i18n = {
monthNames: [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
],
weekdays: [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
],
weekdaysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
firstDayOfWeek: 0,
week: "Week",
calendar: "Calendar",
clear: "Clear",
today: "Today",
cancel: "Cancel",
formatTitle: (monthName, fullYear) => monthName + " " + fullYear,
formatDate: (d: { day: number; month: number; year: number }) =>
[
("0000" + String(d.year)).slice(-4),
("0" + String(d.month + 1)).slice(-2),
("0" + String(d.day)).slice(-2),
].join("-"),
parseDate: (text: string) => {
const parts = text.split("-");
const today = new Date();
let date;
let month = today.getMonth();
let year = today.getFullYear();
if (parts.length === 3) {
year = parseInt(parts[0]);
if (parts[0].length < 3 && year >= 0) {
year += year < 50 ? 2000 : 1900;
}
month = parseInt(parts[1]) - 1;
date = parseInt(parts[2]);
} else if (parts.length === 2) {
month = parseInt(parts[0]) - 1;
date = parseInt(parts[1]);
} else if (parts.length === 1) {
date = parseInt(parts[0]);
}
const loadDatePickerDialog = () => import("./ha-dialog-date-picker");

if (date !== undefined) {
return { day: date, month, year };
}
return undefined;
},
export interface datePickerDialogParams {
value?: string;
min?: string;
max?: string;
locale?: string;
onChange: (value: string) => void;
}

const showDatePickerDialog = (
element: HTMLElement,
dialogParams: datePickerDialogParams
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "ha-dialog-date-picker",
dialogImport: loadDatePickerDialog,
dialogParams,
});
};
@customElement("ha-date-input")
export class HaDateInput extends LitElement {
@property({ attribute: false }) public locale!: HomeAssistant["locale"];

@property() public value?: string;

@property({ type: Boolean }) public disabled = false;

@property() public label?: string;

@query("vaadin-date-picker-light", true) private _datePicker;

private _inited = false;

updated(changedProps: PropertyValues) {
if (changedProps.has("value")) {
this._datePicker.value = this.value;
this._inited = true;
}
}

render() {
return html`<vaadin-date-picker-light
return html`<paper-input
.label=${this.label}
.disabled=${this.disabled}
@value-changed=${this._valueChanged}
attr-for-value="value"
.i18n=${i18n}
no-label-float
@click=${this._openDialog}
.value=${this.value
? formatDateNumeric(new Date(this.value), this.locale)
: ""}
>
<paper-input
.label=${this.label}
.disabled=${this.disabled}
no-label-float
>
<ha-svg-icon slot="suffix" .path=${mdiCalendar}></ha-svg-icon>
</paper-input>
</vaadin-date-picker-light>`;
<ha-svg-icon slot="suffix" .path=${mdiCalendar}></ha-svg-icon>
</paper-input>`;
}

private _valueChanged(ev: CustomEvent) {
if (
!this.value ||
(this._inited && !this._compareStringDates(ev.detail.value, this.value))
) {
this.value = ev.detail.value;
fireEvent(this, "change");
fireEvent(this, "value-changed", { value: ev.detail.value });
private _openDialog() {
if (this.disabled) {
return;
}
showDatePickerDialog(this, {
min: "1970-01-01",
value: this.value,
onChange: (value) => this._valueChanged(value),
locale: this.locale.language,
});
}

private _compareStringDates(a: string, b: string): boolean {
const aParts = a.split("-");
const bParts = b.split("-");
let i = 0;
for (const aPart of aParts) {
if (Number(aPart) !== Number(bParts[i])) {
return false;
}
i++;
private _valueChanged(value: string) {
if (this.value !== value) {
this.value = value;
fireEvent(this, "change");
fireEvent(this, "value-changed", { value });
}
return true;
}

static get styles(): CSSResultGroup {
Expand Down
106 changes: 106 additions & 0 deletions src/components/ha-dialog-date-picker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import "@material/mwc-button/mwc-button";
import "app-datepicker";
import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import { haStyleDialog } from "../resources/styles";
import { datePickerDialogParams } from "./ha-date-input";
import "./ha-dialog";

@customElement("ha-dialog-date-picker")
export class HaDialogDatePicker extends LitElement {
@property() public value?: string;

@property({ type: Boolean }) public disabled = false;

@property() public label?: string;

@state() private _params?: datePickerDialogParams;

@state() private _value?: string;

public showDialog(params: datePickerDialogParams): void {
this._params = params;
this._value = params.value;
}

public closeDialog() {
this._params = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}

render() {
if (!this._params) {
return html``;
}
return html`<ha-dialog open @closed=${this.closeDialog}>
<app-datepicker
.value=${this._value}
.min=${this._params.min}
.max=${this._params.max}
.locale=${this._params.locale}
@datepicker-value-updated=${this._valueChanged}
></app-datepicker>
<mwc-button slot="secondaryAction" @click=${this._setToday}
>today</mwc-button
>
<mwc-button slot="primaryAction" dialogaction="cancel" class="cancel-btn">
cancel
</mwc-button>
<mwc-button slot="primaryAction" @click=${this._setValue}>ok</mwc-button>
</ha-dialog>`;
}

private _valueChanged(ev: CustomEvent) {
this._value = ev.detail.value;
}

private _setToday() {
this._value = new Date().toISOString().split("T")[0];
}

private _setValue() {
this._params?.onChange(this._value!);
this.closeDialog();
}

static styles = [
haStyleDialog,
css`
ha-dialog {
--dialog-content-padding: 0;
--justify-action-buttons: space-between;
}
app-datepicker {
--app-datepicker-accent-color: var(--primary-color);
--app-datepicker-bg-color: transparent;
--app-datepicker-color: var(--primary-text-color);
--app-datepicker-disabled-day-color: var(--disabled-text-color);
--app-datepicker-focused-day-color: var(--text-primary-color);
--app-datepicker-focused-year-bg-color: var(--primary-color);
--app-datepicker-selector-color: var(--secondary-text-color);
--app-datepicker-separator-color: var(--divider-color);
--app-datepicker-weekday-color: var(--secondary-text-color);
}
app-datepicker::part(calendar-day):focus {
outline: none;
}
@media all and (min-width: 450px) {
ha-dialog {
--mdc-dialog-min-width: 300px;
}
}
@media all and (max-width: 450px), all and (max-height: 500px) {
app-datepicker {
width: 100%;
}
}
`,
];
}

declare global {
interface HTMLElementTagNameMap {
"ha-dialog-date-picker": HaDialogDatePicker;
}
}
1 change: 1 addition & 0 deletions src/dialogs/more-info/controls/more-info-input_datetime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class MoreInfoInputDatetime extends LitElement {
this.stateObj.attributes.has_date
? html`
<ha-date-input
.locale=${this.hass.locale}
.value=${`${this.stateObj.attributes.year}-${this.stateObj.attributes.month}-${this.stateObj.attributes.day}`}
.disabled=${UNAVAILABLE_STATES.includes(this.stateObj.state)}
@value-changed=${this._dateChanged}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
${stateObj.attributes.has_date
? html`
<ha-date-input
.locale=${this.hass.locale}
.disabled=${UNAVAILABLE_STATES.includes(stateObj.state)}
.value=${`${stateObj.attributes.year}-${stateObj.attributes.month}-${stateObj.attributes.day}`}
@value-changed=${this._dateChanged}
Expand Down

0 comments on commit 45e6ec1

Please sign in to comment.