mirror of
https://github.com/home-assistant/frontend.git
synced 2026-08-04 05:30:06 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| aa5e92b04f |
@@ -7,8 +7,6 @@ description: Home Assistant frontend component patterns. Use when implementing o
|
||||
|
||||
Use this skill when creating or reviewing Home Assistant UI components and common interaction patterns.
|
||||
|
||||
Cross-load `ha-frontend-events` when component work includes event listener typing, custom event dispatch, or event-map declarations.
|
||||
|
||||
## Dialogs
|
||||
|
||||
Open dialogs through the fire-event pattern:
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
---
|
||||
name: ha-frontend-events
|
||||
description: Home Assistant frontend event patterns. Use when typing event handlers, using HASSDomEvent types, dispatching with fireEvent, or declaring HASSDomEvents and event maps.
|
||||
---
|
||||
|
||||
# HA Frontend Events
|
||||
|
||||
Use this skill when implementing or reviewing event listeners and custom event contracts. Cross-load `ha-frontend-components` when the work also involves dialogs, forms, alerts, shortcuts, tooltips, panels, Lovelace cards, or buttons.
|
||||
|
||||
## Event Handling
|
||||
|
||||
Use the event types from `src/common/dom/fire_event.ts` instead of plain `Event`, generic `CustomEvent`, or element casts when they express the handler contract:
|
||||
|
||||
- Use `HASSDomCurrentTargetEvent<T>` to read the element on which the listener was registered through `ev.currentTarget`.
|
||||
- Use `HASSDomTargetEvent<T>` only to read the element that originated the event through `ev.target`.
|
||||
- Use `HASSDomEvent<T>` to read a custom event payload through `ev.detail`.
|
||||
- Use `ValueChangedEvent<T>` from `src/types.ts` for the standard `value-changed` event.
|
||||
- Prefer an event type exported by the component being listened to, such as `HaSelectSelectEvent<T, Clearable>` or `HaDropdownSelectEvent<TValue, TData>`, over reconstructing its detail type.
|
||||
- Use `ActionHandlerEvent` from `src/data/lovelace/action_handler.ts` for Lovelace tap, hold, and double-tap handlers.
|
||||
|
||||
Import event and element types with `import type`:
|
||||
|
||||
```ts
|
||||
import type {
|
||||
HASSDomCurrentTargetEvent,
|
||||
HASSDomEvent,
|
||||
HASSDomTargetEvent,
|
||||
} from "../common/dom/fire_event";
|
||||
import type { HaCheckbox } from "../components/ha-checkbox";
|
||||
import type { HaEntityPicker } from "../components/entity/ha-entity-picker";
|
||||
import type { HaRadioGroup } from "../components/radio/ha-radio-group";
|
||||
import type { ValueChangedEvent } from "../types";
|
||||
```
|
||||
|
||||
Type the handler so the selected property can be read directly. Do not cast `ev.currentTarget` or assign it to a single-use variable:
|
||||
|
||||
```ts
|
||||
private _scopeChanged(ev: HASSDomCurrentTargetEvent<HaRadioGroup>): void {
|
||||
this._scope = ev.currentTarget.value;
|
||||
}
|
||||
|
||||
private _checkedChanged(ev: HASSDomTargetEvent<HaCheckbox>): void {
|
||||
this._checked = ev.target.checked;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: ValueChangedEvent<string>): void {
|
||||
this._value = ev.detail.value;
|
||||
}
|
||||
|
||||
private _itemSelected(ev: HASSDomEvent<{ id: string }>): void {
|
||||
this._selectedId = ev.detail.id;
|
||||
}
|
||||
```
|
||||
|
||||
Use intersections when a handler needs more than one facet of an event. Keep the native event type when the handler reads native fields such as `key`, modifier keys, `dataTransfer`, or focus relationships:
|
||||
|
||||
```ts
|
||||
private _entityChanged(
|
||||
ev: ValueChangedEvent<string> & HASSDomCurrentTargetEvent<HaEntityPicker>
|
||||
): void {
|
||||
ev.currentTarget.value = ev.detail.value;
|
||||
}
|
||||
|
||||
private _keyDown(
|
||||
ev: KeyboardEvent & HASSDomCurrentTargetEvent<HTMLInputElement>
|
||||
): void {
|
||||
if (ev.key === "Enter") {
|
||||
this._submit(ev.currentTarget.value);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Dispatch Home Assistant component events with `fireEvent()` instead of constructing `Event` or `CustomEvent` directly. Register the event name and detail type by augmenting `HASSDomEvents`; use `undefined` when an event has no detail. `fireEvent()` constrains event names and supplied detail, and events bubble and cross shadow boundaries by default:
|
||||
|
||||
```ts
|
||||
fireEvent(this, "item-selected", { id: item.id });
|
||||
fireEvent(this, "refresh-requested");
|
||||
```
|
||||
|
||||
When an event is already registered, derive handler and listener types from its registration rather than repeating the payload shape:
|
||||
|
||||
```ts
|
||||
private _itemSelected(
|
||||
ev: HASSDomEvent<HASSDomEvents["item-selected"]>
|
||||
): void {
|
||||
this._selectedId = ev.detail.id;
|
||||
}
|
||||
```
|
||||
|
||||
`HASSDomEvents` types `fireEvent()` calls. Augment `HTMLElementEventMap` for typed listeners on HTML elements, or `GlobalEventHandlersEventMap` when the event is handled on global event targets.
|
||||
|
||||
In component files, prefer placing global event declarations after the class at the bottom of the file. Preserve the existing placement when editing established files; foundational type, helper, and mixin files commonly keep declarations near the top before their consumers.
|
||||
|
||||
```ts
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
"item-selected": { id: string };
|
||||
"refresh-requested": undefined;
|
||||
}
|
||||
|
||||
interface HTMLElementEventMap {
|
||||
"item-selected": HASSDomEvent<HASSDomEvents["item-selected"]>;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -70,4 +70,4 @@ Configuration and props:
|
||||
- Identify behavioral regressions, bugs, accessibility issues, and missing tests first.
|
||||
- Keep style-only comments secondary unless they affect maintainability or user experience.
|
||||
- Prefer small, direct fixes over large refactors during review follow-up.
|
||||
- Cross-load `ha-frontend-contexts`, `ha-frontend-components`, `ha-frontend-events`, `ha-frontend-styling`, `ha-frontend-testing`, or `ha-frontend-user-facing-text` when a finding falls in that area.
|
||||
- Cross-load `ha-frontend-contexts`, `ha-frontend-components`, `ha-frontend-styling`, `ha-frontend-testing`, or `ha-frontend-user-facing-text` when a finding falls in that area.
|
||||
|
||||
@@ -40,7 +40,6 @@ Detailed guidance lives in project skills under `.agents/skills/`. Load the matc
|
||||
|
||||
- `ha-frontend-contexts`: Lit contexts, `hass` migration, and rerender-sensitive state access.
|
||||
- `ha-frontend-components`: dialogs, forms, alerts, shortcuts, tooltips, panels, and Lovelace cards.
|
||||
- `ha-frontend-events`: event handler typing, custom event dispatch, and event-map declarations.
|
||||
- `ha-frontend-styling`: theme variables, spacing tokens, responsive layout, RTL, and view transitions.
|
||||
- `ha-frontend-testing`: lint, typecheck, Vitest, Playwright e2e dev servers, and benchmarks.
|
||||
- `ha-frontend-user-facing-text`: localization, terminology, sentence case, and Home Assistant text style.
|
||||
|
||||
@@ -294,3 +294,26 @@ export const formatCallyDateRange = (
|
||||
|
||||
return `${startDate}/${endDate}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* August 2021, for calendar days coming out of cally.
|
||||
*
|
||||
* cally hands out calendar days as `Date` objects anchored to UTC midnight, and
|
||||
* formats its own headings in UTC too. Anything derived from a cally event has
|
||||
* to be formatted the same way: the resolved time zone shifts the day back for
|
||||
* negative UTC offsets, which becomes a wrong month — and in January a wrong
|
||||
* year — whenever the day is the 1st.
|
||||
*/
|
||||
export const formatCallyMonthYear = (
|
||||
dateObj: Date,
|
||||
locale: FrontendLocaleData
|
||||
) => formatCallyMonthYearMem(locale.language).format(dateObj);
|
||||
|
||||
const formatCallyMonthYearMem = memoizeOne(
|
||||
(language: string) =>
|
||||
new Intl.DateTimeFormat(language, {
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
timeZone: "UTC",
|
||||
})
|
||||
);
|
||||
|
||||
@@ -9,8 +9,8 @@ import { customElement, property, queryAll, state } from "lit/decorators";
|
||||
import { firstWeekdayIndex } from "../../common/datetime/first_weekday";
|
||||
import {
|
||||
formatCallyDateRange,
|
||||
formatDateMonth,
|
||||
formatDateYear,
|
||||
formatCallyMonthYear,
|
||||
formatDateMonthYear,
|
||||
formatISODateOnly,
|
||||
} from "../../common/datetime/format_date";
|
||||
import { transform } from "../../common/decorators/transform";
|
||||
@@ -56,13 +56,16 @@ export class DateRangePicker extends MobileAwareMixin(LitElement) {
|
||||
})
|
||||
private _hassConfig!: HassConfig;
|
||||
|
||||
/** used to show month in calendar-range header */
|
||||
@state() private _pickerMonth?: string;
|
||||
/** used to show month and year in calendar-range header */
|
||||
@state() private _pickerMonthYear?: string;
|
||||
|
||||
/** used to show year in calendar-date header */
|
||||
@state() private _pickerYear?: string;
|
||||
|
||||
/** used for today to navigate focus in calendar-range */
|
||||
/**
|
||||
* used for today to navigate focus in calendar-range
|
||||
*
|
||||
* Always mirrors the day calendar-range has focused, never cleared: once this
|
||||
* has held a date, rendering `undefined` over it makes cally fall back to the
|
||||
* selected range and page the calendar away from where the user is.
|
||||
*/
|
||||
@state() private _focusDate?: string;
|
||||
|
||||
@state() private _dateValue?: string;
|
||||
@@ -88,12 +91,7 @@ export class DateRangePicker extends MobileAwareMixin(LitElement) {
|
||||
this._hassConfig
|
||||
)
|
||||
: undefined;
|
||||
this._pickerMonth = formatDateMonth(
|
||||
date,
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
);
|
||||
this._pickerYear = formatDateYear(
|
||||
this._pickerMonthYear = formatDateMonthYear(
|
||||
date,
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
@@ -163,9 +161,7 @@ export class DateRangePicker extends MobileAwareMixin(LitElement) {
|
||||
slot="previous"
|
||||
></ha-icon-button-prev>
|
||||
<div class="heading" slot="heading">
|
||||
<span class="month-year"
|
||||
>${this._pickerMonth} ${this._pickerYear}</span
|
||||
>
|
||||
<span class="month-year">${this._pickerMonthYear}</span>
|
||||
<ha-icon-button
|
||||
@click=${this._focusToday}
|
||||
.path=${mdiCalendarToday}
|
||||
@@ -229,12 +225,7 @@ export class DateRangePicker extends MobileAwareMixin(LitElement) {
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
);
|
||||
this._pickerMonth = formatDateMonth(
|
||||
date,
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
);
|
||||
this._pickerYear = formatDateYear(
|
||||
this._pickerMonthYear = formatDateMonthYear(
|
||||
date,
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
@@ -308,24 +299,15 @@ export class DateRangePicker extends MobileAwareMixin(LitElement) {
|
||||
}
|
||||
|
||||
private _focusChanged(ev: CustomEvent<Date>) {
|
||||
const date = ev.detail;
|
||||
this._pickerMonth = formatDateMonth(
|
||||
date,
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
);
|
||||
this._pickerYear = formatDateYear(
|
||||
date,
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
);
|
||||
this._focusDate = undefined;
|
||||
const dateElement = ev.target as HTMLElementTagNameMap["calendar-range"];
|
||||
this._pickerMonthYear = formatCallyMonthYear(ev.detail, this._i18n.locale);
|
||||
this._focusDate = dateElement.focusedDate;
|
||||
}
|
||||
|
||||
private _handleChange(ev: CustomEvent) {
|
||||
const dateElement = ev.target as HTMLElementTagNameMap["calendar-range"];
|
||||
this._dateValue = dateElement.value;
|
||||
this._focusDate = undefined;
|
||||
this._focusDate = dateElement.focusedDate;
|
||||
}
|
||||
|
||||
private _clickDateRangeChip(ev: Event) {
|
||||
|
||||
@@ -6,7 +6,8 @@ import type { HassConfig } from "home-assistant-js-websocket/dist/types";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, state } from "lit/decorators";
|
||||
import {
|
||||
formatDateMonth,
|
||||
formatCallyMonthYear,
|
||||
formatDateMonthYear,
|
||||
formatDateShort,
|
||||
formatDateYear,
|
||||
formatISODateOnly,
|
||||
@@ -56,13 +57,16 @@ export class HaDialogDatePicker extends DialogMixin<DatePickerDialogParams>(
|
||||
dateString: string;
|
||||
};
|
||||
|
||||
/** used to show month in calendar-date header */
|
||||
@state() private _pickerMonth?: string;
|
||||
/** used to show month and year in calendar-date header */
|
||||
@state() private _pickerMonthYear?: string;
|
||||
|
||||
/** used to show year in calendar-date header */
|
||||
@state() private _pickerYear?: string;
|
||||
|
||||
/** used for today to navigate focus in cally-calendar-date */
|
||||
/**
|
||||
* used for today to navigate focus in cally-calendar-date
|
||||
*
|
||||
* Always mirrors the day calendar-date has focused, never cleared: once this
|
||||
* has held a date, rendering `undefined` over it makes cally fall back to the
|
||||
* selected value and page the calendar away from where the user is.
|
||||
*/
|
||||
@state() private _focusDate?: string;
|
||||
|
||||
public connectedCallback() {
|
||||
@@ -71,12 +75,7 @@ export class HaDialogDatePicker extends DialogMixin<DatePickerDialogParams>(
|
||||
if (this.params) {
|
||||
const date = valueToDate(this.params.value);
|
||||
|
||||
this._pickerYear = formatDateYear(
|
||||
date,
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
);
|
||||
this._pickerMonth = formatDateMonth(
|
||||
this._pickerMonthYear = formatDateMonthYear(
|
||||
date,
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
@@ -84,7 +83,7 @@ export class HaDialogDatePicker extends DialogMixin<DatePickerDialogParams>(
|
||||
|
||||
this._value = this.params.value
|
||||
? {
|
||||
year: this._pickerYear,
|
||||
year: formatDateYear(date, this._i18n.locale, this._hassConfig),
|
||||
title: formatDateShort(date, this._i18n.locale, this._hassConfig),
|
||||
dateString: formatISODateOnly(
|
||||
date,
|
||||
@@ -140,9 +139,7 @@ export class HaDialogDatePicker extends DialogMixin<DatePickerDialogParams>(
|
||||
slot="previous"
|
||||
></ha-icon-button-prev>
|
||||
<div class="heading" slot="heading">
|
||||
<span class="month-year"
|
||||
>${this._pickerMonth} ${this._pickerYear}</span
|
||||
>
|
||||
<span class="month-year">${this._pickerMonthYear}</span>
|
||||
<ha-icon-button
|
||||
@click=${this._setToday}
|
||||
.path=${mdiCalendarToday}
|
||||
@@ -185,12 +182,7 @@ export class HaDialogDatePicker extends DialogMixin<DatePickerDialogParams>(
|
||||
|
||||
if (setFocusDay) {
|
||||
this._focusDate = this._value.dateString;
|
||||
this._pickerMonth = formatDateMonth(
|
||||
date,
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
);
|
||||
this._pickerYear = formatDateYear(
|
||||
this._pickerMonthYear = formatDateMonthYear(
|
||||
date,
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
@@ -199,18 +191,9 @@ export class HaDialogDatePicker extends DialogMixin<DatePickerDialogParams>(
|
||||
}
|
||||
|
||||
private _focusChanged(ev: CustomEvent<Date>) {
|
||||
const date = ev.detail;
|
||||
this._pickerMonth = formatDateMonth(
|
||||
date,
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
);
|
||||
this._pickerYear = formatDateYear(
|
||||
date,
|
||||
this._i18n.locale,
|
||||
this._hassConfig
|
||||
);
|
||||
this._focusDate = undefined;
|
||||
const dateElement = ev.target as CalendarDate;
|
||||
this._pickerMonthYear = formatCallyMonthYear(ev.detail, this._i18n.locale);
|
||||
this._focusDate = dateElement.focusedDate;
|
||||
}
|
||||
|
||||
private _clear() {
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import type { HASSDomTargetEvent } from "../../../common/dom/fire_event";
|
||||
import { DirtyStateProviderMixin } from "../../../mixins/dirty-state-provider-mixin";
|
||||
import "../../../components/entity/ha-entity-picker";
|
||||
import type { HaEntityPicker } from "../../../components/entity/ha-entity-picker";
|
||||
@@ -456,7 +455,7 @@ class DialogAreaDetail
|
||||
return deviceReg && deviceReg.area_id === areaId;
|
||||
};
|
||||
|
||||
private _nameChanged(ev: InputEvent & HASSDomTargetEvent<HaInput>) {
|
||||
private _nameChanged(ev: InputEvent) {
|
||||
this._error = undefined;
|
||||
this._name = (ev.target as HaInput).value ?? "";
|
||||
this._updateDirtyState(this._currentState());
|
||||
@@ -480,9 +479,7 @@ class DialogAreaDetail
|
||||
this._updateDirtyState(this._currentState());
|
||||
}
|
||||
|
||||
private _pictureChanged(
|
||||
ev: ValueChangedEvent<string | null> & HASSDomTargetEvent<HaPictureUpload>
|
||||
) {
|
||||
private _pictureChanged(ev: ValueChangedEvent<string | null>) {
|
||||
this._error = undefined;
|
||||
this._picture = (ev.target as HaPictureUpload).value;
|
||||
this._updateDirtyState(this._currentState());
|
||||
@@ -493,9 +490,7 @@ class DialogAreaDetail
|
||||
this._updateDirtyState(this._currentState());
|
||||
}
|
||||
|
||||
private _sensorChanged(
|
||||
ev: ValueChangedEvent<string> & HASSDomTargetEvent<HaEntityPicker>
|
||||
): void {
|
||||
private _sensorChanged(ev: CustomEvent): void {
|
||||
const deviceClass = (ev.target as HaEntityPicker).includeDeviceClasses![0];
|
||||
const key = `_${deviceClass}Entity`;
|
||||
this[key] = ev.detail.value || null;
|
||||
|
||||
@@ -5,7 +5,6 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { repeat } from "lit/directives/repeat";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import type { HASSDomTargetEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/chips/ha-chip-set";
|
||||
import "../../../components/chips/ha-input-chip";
|
||||
import "../../../components/ha-alert";
|
||||
@@ -337,13 +336,13 @@ class DialogFloorDetail extends DirtyStateProviderMixin<FloorFormState>()(
|
||||
this._updateDirtyState(this._currentState());
|
||||
}
|
||||
|
||||
private _nameChanged(ev: InputEvent & HASSDomTargetEvent<HaInput>) {
|
||||
private _nameChanged(ev: InputEvent) {
|
||||
this._error = undefined;
|
||||
this._name = (ev.target as HaInput).value ?? "";
|
||||
this._updateDirtyState(this._currentState());
|
||||
}
|
||||
|
||||
private _levelChanged(ev: InputEvent & HASSDomTargetEvent<HaInput>) {
|
||||
private _levelChanged(ev: InputEvent) {
|
||||
this._error = undefined;
|
||||
this._level =
|
||||
(ev.target as HaInput).value === ""
|
||||
|
||||
@@ -2,7 +2,6 @@ import { mdiClose, mdiOpenInNew } from "@mdi/js";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import type { HASSDomTargetEvent } from "../../../common/dom/fire_event";
|
||||
import { withViewTransition } from "../../../common/util/view-transition";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-button";
|
||||
@@ -280,7 +279,7 @@ class DialogImportBlueprint extends DirtyStateProviderMixin<BlueprintImportState
|
||||
});
|
||||
}
|
||||
|
||||
private _inputChanged(ev: HASSDomTargetEvent<HaInput>) {
|
||||
private _inputChanged(ev: Event) {
|
||||
this._updateDirtyState({
|
||||
value: (ev.target as HaInput).value ?? "",
|
||||
hasResult: !!this._result,
|
||||
|
||||
@@ -13,10 +13,7 @@ import { LitElement, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
import type {
|
||||
HASSDomCurrentTargetEvent,
|
||||
HASSDomEvent,
|
||||
} from "../../../common/dom/fire_event";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
@@ -486,7 +483,7 @@ class HaBlueprintOverview extends LitElement {
|
||||
this._createNew(blueprint);
|
||||
}
|
||||
|
||||
private _handleUsageClick = (ev: HASSDomCurrentTargetEvent<HTMLElement>) => {
|
||||
private _handleUsageClick = (ev: Event) => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
const target = ev.currentTarget as HTMLElement | null;
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { HASSDomEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/entity/ha-statistic-picker";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-dialog";
|
||||
@@ -341,7 +340,7 @@ export class DialogEnergyBatterySettings
|
||||
}
|
||||
|
||||
private _handlePowerConfigChanged(
|
||||
ev: HASSDomEvent<HASSDomEvents["power-config-changed"]>
|
||||
ev: CustomEvent<{ powerType: PowerType; powerConfig: PowerConfig }>
|
||||
) {
|
||||
this._powerType = ev.detail.powerType;
|
||||
this._powerConfig = ev.detail.powerConfig;
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../../common/dom/fire_event";
|
||||
import type { LocalizeKeys } from "../../../../common/translations/localize";
|
||||
import "../../../../components/ha-alert";
|
||||
import "../../../../components/ha-button";
|
||||
@@ -215,7 +214,7 @@ export class DialogEnergyCustomise
|
||||
`;
|
||||
}
|
||||
|
||||
private _toggleCard = (ev: HASSDomCurrentTargetEvent<HaSwitch>): void => {
|
||||
private _toggleCard = (ev: Event): void => {
|
||||
const target = ev.currentTarget as HaSwitch;
|
||||
const cardKey = target.dataset.cardKey;
|
||||
if (!cardKey) {
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../components/entity/ha-statistic-picker";
|
||||
import "../../../../components/ha-button";
|
||||
@@ -354,7 +353,7 @@ export class DialogEnergyGasSettings
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleCostChanged(ev: HASSDomCurrentTargetEvent<HaRadioGroup>) {
|
||||
private _handleCostChanged(ev: Event) {
|
||||
this._costs = (ev.currentTarget as HaRadioGroup).value as CostType;
|
||||
this._updateFormDirtyState();
|
||||
}
|
||||
|
||||
@@ -2,10 +2,6 @@ import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type {
|
||||
HASSDomCurrentTargetEvent,
|
||||
HASSDomEvent,
|
||||
} from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../components/entity/ha-statistic-picker";
|
||||
import "../../../../components/ha-button";
|
||||
@@ -597,9 +593,7 @@ export class DialogEnergyGridSettings
|
||||
this._updateFormDirtyState();
|
||||
}
|
||||
|
||||
private _handleImportCostTypeChanged(
|
||||
ev: HASSDomCurrentTargetEvent<HaRadioGroup>
|
||||
) {
|
||||
private _handleImportCostTypeChanged(ev: Event) {
|
||||
this._importCostType = (ev.currentTarget as HaRadioGroup).value as CostType;
|
||||
// Clear other cost fields when switching types
|
||||
this._source = {
|
||||
@@ -611,9 +605,7 @@ export class DialogEnergyGridSettings
|
||||
this._updateFormDirtyState();
|
||||
}
|
||||
|
||||
private _handleExportCostTypeChanged(
|
||||
ev: HASSDomCurrentTargetEvent<HaRadioGroup>
|
||||
) {
|
||||
private _handleExportCostTypeChanged(ev: Event) {
|
||||
this._exportCostType = (ev.currentTarget as HaRadioGroup).value as CostType;
|
||||
// Clear other cost fields when switching types
|
||||
this._source = {
|
||||
@@ -638,7 +630,7 @@ export class DialogEnergyGridSettings
|
||||
this._updateFormDirtyState();
|
||||
}
|
||||
|
||||
private _numberCostChanged(ev: HASSDomCurrentTargetEvent<HTMLInputElement>) {
|
||||
private _numberCostChanged(ev: Event) {
|
||||
const input = ev.currentTarget as HTMLInputElement;
|
||||
const value = input.value ? parseFloat(input.value) : null;
|
||||
this._source = { ...this._source!, number_energy_price: value };
|
||||
@@ -661,9 +653,7 @@ export class DialogEnergyGridSettings
|
||||
this._updateFormDirtyState();
|
||||
}
|
||||
|
||||
private _numberCompensationChanged(
|
||||
ev: HASSDomCurrentTargetEvent<HTMLInputElement>
|
||||
) {
|
||||
private _numberCompensationChanged(ev: Event) {
|
||||
const input = ev.currentTarget as HTMLInputElement;
|
||||
const value = input.value ? parseFloat(input.value) : null;
|
||||
this._source = { ...this._source!, number_energy_price_export: value };
|
||||
@@ -671,7 +661,7 @@ export class DialogEnergyGridSettings
|
||||
}
|
||||
|
||||
private _handlePowerConfigChanged(
|
||||
ev: HASSDomEvent<HASSDomEvents["power-config-changed"]>
|
||||
ev: CustomEvent<{ powerType: PowerType; powerConfig: PowerConfig }>
|
||||
) {
|
||||
this._powerType = ev.detail.powerType;
|
||||
this._powerConfig = ev.detail.powerConfig;
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/entity/ha-statistic-picker";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-checkbox";
|
||||
@@ -291,7 +290,7 @@ export class DialogEnergySolarSettings
|
||||
);
|
||||
}
|
||||
|
||||
private _handleForecastChanged(ev: HASSDomCurrentTargetEvent<HaRadioGroup>) {
|
||||
private _handleForecastChanged(ev: Event) {
|
||||
this._forecast = (ev.currentTarget as HaRadioGroup).value === "true";
|
||||
this._updateFormDirtyState();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../components/entity/ha-statistic-picker";
|
||||
import "../../../../components/ha-button";
|
||||
@@ -290,7 +289,7 @@ export class DialogEnergyWaterSettings
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleCostChanged(ev: HASSDomCurrentTargetEvent<HaRadioGroup>) {
|
||||
private _handleCostChanged(ev: Event) {
|
||||
this._costs = (ev.currentTarget as HaRadioGroup).value as CostType;
|
||||
this._updateFormDirtyState();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||
import type { LocalizeKeys } from "../../../../common/translations/localize";
|
||||
import "../../../../components/entity/ha-statistic-picker";
|
||||
@@ -235,7 +234,7 @@ export class HaEnergyPowerConfig extends LitElement {
|
||||
fireEvent(this, "hass-more-info", { entityId: this.helperEntityId! });
|
||||
}
|
||||
|
||||
private _handlePowerTypeChanged(ev: HASSDomCurrentTargetEvent<HaRadioGroup>) {
|
||||
private _handlePowerTypeChanged(ev: Event) {
|
||||
const newPowerType = (ev.currentTarget as HaRadioGroup).value as PowerType;
|
||||
// Clear power config when switching types
|
||||
fireEvent(this, "power-config-changed", {
|
||||
|
||||
+2
-7
@@ -3,7 +3,6 @@ import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../../../common/dom/fire_event";
|
||||
import { computeDeviceName } from "../../../../../common/entity/compute_device_name";
|
||||
import "../../../../../components/ha-alert";
|
||||
import "../../../../../components/ha-button";
|
||||
@@ -452,9 +451,7 @@ export class BluetoothAdapterInfoPage extends LitElement {
|
||||
return this._formatModeLabel(scannerState.current_mode);
|
||||
}
|
||||
|
||||
private async _handleEnable(
|
||||
ev: HASSDomCurrentTargetEvent<HTMLElement & { entry: ConfigEntry }>
|
||||
) {
|
||||
private async _handleEnable(ev: Event) {
|
||||
const button = ev.currentTarget as HTMLElement & { entry: ConfigEntry };
|
||||
const entryId = button.entry.entry_id;
|
||||
try {
|
||||
@@ -477,9 +474,7 @@ export class BluetoothAdapterInfoPage extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _openOptionFlow(
|
||||
ev: HASSDomCurrentTargetEvent<HTMLElement & { entry: ConfigEntry }>
|
||||
) {
|
||||
private _openOptionFlow(ev: Event) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const button = ev.currentTarget as HTMLElement & { entry: ConfigEntry };
|
||||
|
||||
+2
-7
@@ -3,7 +3,6 @@ import type { CSSResultGroup } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/ha-alert";
|
||||
import "../../../../../components/ha-button";
|
||||
import "../../../../../components/ha-dialog-footer";
|
||||
@@ -212,9 +211,7 @@ class DialogMatterLockManage extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleUserClick(
|
||||
ev: HASSDomCurrentTargetEvent<HTMLElement & { user: MatterLockUser }>
|
||||
): void {
|
||||
private _handleUserClick(ev: Event): void {
|
||||
// Ignore clicks that originated from the delete button
|
||||
const path = ev.composedPath();
|
||||
if (path.some((el) => (el as HTMLElement).tagName === "HA-ICON-BUTTON")) {
|
||||
@@ -224,9 +221,7 @@ class DialogMatterLockManage extends LitElement {
|
||||
this._editUser(user);
|
||||
}
|
||||
|
||||
private _handleDeleteUserClick(
|
||||
ev: HASSDomCurrentTargetEvent<HTMLElement & { user: MatterLockUser }>
|
||||
): void {
|
||||
private _handleDeleteUserClick(ev: Event): void {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const user = (ev.currentTarget as any).user as MatterLockUser;
|
||||
|
||||
@@ -11,7 +11,10 @@ import { addGroup, fetchGroupableDevices } from "../../../../../data/zha";
|
||||
import "../../../../../layouts/hass-subpage";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import "./zha-device-endpoint-list";
|
||||
import type { ZHADeviceEndpointList } from "./zha-device-endpoint-list";
|
||||
import type {
|
||||
DeviceEndpointSelectionChangedEvent,
|
||||
ZHADeviceEndpointList,
|
||||
} from "./zha-device-endpoint-list";
|
||||
|
||||
@customElement("zha-add-group-page")
|
||||
export class ZHAAddGroupPage extends LitElement {
|
||||
@@ -128,7 +131,7 @@ export class ZHAAddGroupPage extends LitElement {
|
||||
}
|
||||
|
||||
private _handleAddSelectionChanged(
|
||||
ev: HASSDomEvent<HASSDomEvents["selection-changed"]>
|
||||
ev: HASSDomEvent<DeviceEndpointSelectionChangedEvent>
|
||||
): void {
|
||||
this._selectedDevicesToAdd = ev.detail.value;
|
||||
}
|
||||
|
||||
@@ -4,15 +4,10 @@ import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { repeat } from "lit/directives/repeat";
|
||||
import type {
|
||||
HASSDomCurrentTargetEvent,
|
||||
HASSDomEvent,
|
||||
} from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "../../../../../components/ha-list";
|
||||
import "../../../../../components/input/ha-input-search";
|
||||
import type { HaInputSearch } from "../../../../../components/input/ha-input-search";
|
||||
import "../../../../../components/item/ha-list-item-base";
|
||||
import "../../../../../components/item/ha-list-item-option";
|
||||
import type { HaListItemOption } from "../../../../../components/item/ha-list-item-option";
|
||||
@@ -274,16 +269,11 @@ export class ZHADeviceEndpointList extends LitElement {
|
||||
.join(" · ");
|
||||
}
|
||||
|
||||
private _handleFilterChanged(
|
||||
ev: HASSDomCurrentTargetEvent<HaInputSearch>
|
||||
): void {
|
||||
this._filter = ev.currentTarget.value ?? "";
|
||||
private _handleFilterChanged(ev: Event): void {
|
||||
this._filter = (ev.currentTarget as HTMLInputElement).value;
|
||||
}
|
||||
|
||||
private _handleItemSelected(
|
||||
ev: HASSDomEvent<HASSDomEvents["ha-list-item-selected"]> &
|
||||
HASSDomCurrentTargetEvent<HaListSelectable>
|
||||
): void {
|
||||
private _handleItemSelected(ev: CustomEvent<number>): void {
|
||||
const list = ev.currentTarget as HaListSelectable;
|
||||
let selectedDeviceIds = this._selectedDeviceIds;
|
||||
|
||||
@@ -300,10 +290,7 @@ export class ZHADeviceEndpointList extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _handleItemDeselected(
|
||||
ev: HASSDomEvent<HASSDomEvents["ha-list-item-deselected"]> &
|
||||
HASSDomCurrentTargetEvent<HaListSelectable>
|
||||
): void {
|
||||
private _handleItemDeselected(ev: CustomEvent<number>): void {
|
||||
const list = ev.currentTarget as HaListSelectable;
|
||||
let selectedDeviceIds = this._selectedDeviceIds;
|
||||
|
||||
|
||||
@@ -19,7 +19,10 @@ import "../../../../../layouts/hass-subpage";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
import "./zha-device-endpoint-list";
|
||||
import type { ZHADeviceEndpointList } from "./zha-device-endpoint-list";
|
||||
import type {
|
||||
DeviceEndpointSelectionChangedEvent,
|
||||
ZHADeviceEndpointList,
|
||||
} from "./zha-device-endpoint-list";
|
||||
import { showZHAAddGroupMembersDialog } from "./show-dialog-zha-add-group-members";
|
||||
|
||||
@customElement("zha-group-page")
|
||||
@@ -199,7 +202,7 @@ export class ZHAGroupPage extends LitElement {
|
||||
}
|
||||
|
||||
private _handleRemoveSelectionChanged(
|
||||
ev: HASSDomEvent<HASSDomEvents["selection-changed"]>
|
||||
ev: HASSDomEvent<DeviceEndpointSelectionChangedEvent>
|
||||
): void {
|
||||
this._selectedDevicesToRemove = ev.detail.value;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/buttons/ha-progress-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-md-list";
|
||||
import "../../../../../components/ha-md-list-item";
|
||||
import "../../../../../components/ha-select";
|
||||
import "../../../../../components/input/ha-input";
|
||||
import type { HaInput } from "../../../../../components/input/ha-input";
|
||||
import "../../../../../components/ha-switch";
|
||||
import type { HaSwitch } from "../../../../../components/ha-switch";
|
||||
import type { ZHAConfiguration } from "../../../../../data/zha";
|
||||
import {
|
||||
fetchZHAConfiguration,
|
||||
@@ -21,8 +18,6 @@ import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../../../../types";
|
||||
|
||||
const PREDEFINED_TIMEOUTS = [1800, 3600, 7200, 21600, 43200, 86400];
|
||||
type ZHASwitchChangeEvent = HASSDomCurrentTargetEvent<HaSwitch>;
|
||||
type ZHAInputChangeEvent = HASSDomCurrentTargetEvent<HaInput>;
|
||||
|
||||
@customElement("zha-options-page")
|
||||
class ZHAOptionsPage extends LitElement {
|
||||
@@ -350,54 +345,53 @@ class ZHAOptionsPage extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _enableIdentifyOnJoinChanged(ev: ZHASwitchChangeEvent): void {
|
||||
this._configuration!.data.zha_options.enable_identify_on_join =
|
||||
ev.currentTarget.checked;
|
||||
private _enableIdentifyOnJoinChanged(ev: Event): void {
|
||||
const checked = (ev.target as HTMLInputElement).checked;
|
||||
this._configuration!.data.zha_options.enable_identify_on_join = checked;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private _enhancedLightTransitionChanged(ev: ZHASwitchChangeEvent): void {
|
||||
this._configuration!.data.zha_options.enhanced_light_transition =
|
||||
ev.currentTarget.checked;
|
||||
private _enhancedLightTransitionChanged(ev: Event): void {
|
||||
const checked = (ev.target as HTMLInputElement).checked;
|
||||
this._configuration!.data.zha_options.enhanced_light_transition = checked;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private _lightTransitioningFlagChanged(ev: ZHASwitchChangeEvent): void {
|
||||
this._configuration!.data.zha_options.light_transitioning_flag =
|
||||
ev.currentTarget.checked;
|
||||
private _lightTransitioningFlagChanged(ev: Event): void {
|
||||
const checked = (ev.target as HTMLInputElement).checked;
|
||||
this._configuration!.data.zha_options.light_transitioning_flag = checked;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private _groupMembersAssumeStateChanged(ev: ZHASwitchChangeEvent): void {
|
||||
this._configuration!.data.zha_options.group_members_assume_state =
|
||||
ev.currentTarget.checked;
|
||||
private _groupMembersAssumeStateChanged(ev: Event): void {
|
||||
const checked = (ev.target as HTMLInputElement).checked;
|
||||
this._configuration!.data.zha_options.group_members_assume_state = checked;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private _enableMainsStartupPollingChanged(ev: ZHASwitchChangeEvent): void {
|
||||
private _enableMainsStartupPollingChanged(ev: Event): void {
|
||||
const checked = (ev.target as HTMLInputElement).checked;
|
||||
this._configuration!.data.zha_options.enable_mains_startup_polling =
|
||||
ev.currentTarget.checked;
|
||||
checked;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private _defaultLightTransitionChanged(ev: ZHAInputChangeEvent): void {
|
||||
this._configuration!.data.zha_options.default_light_transition = Number(
|
||||
ev.currentTarget.value
|
||||
);
|
||||
private _defaultLightTransitionChanged(ev: Event): void {
|
||||
const value = Number((ev.target as HTMLInputElement).value);
|
||||
this._configuration!.data.zha_options.default_light_transition = value;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private _customMainsSecondsChanged(ev: ZHAInputChangeEvent): void {
|
||||
this._configuration!.data.zha_options.consider_unavailable_mains = Number(
|
||||
ev.currentTarget.value
|
||||
);
|
||||
private _customMainsSecondsChanged(ev: Event): void {
|
||||
const seconds = Number((ev.target as HTMLInputElement).value);
|
||||
this._configuration!.data.zha_options.consider_unavailable_mains = seconds;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private _customBatterySecondsChanged(ev: ZHAInputChangeEvent): void {
|
||||
this._configuration!.data.zha_options.consider_unavailable_battery = Number(
|
||||
ev.currentTarget.value
|
||||
);
|
||||
private _customBatterySecondsChanged(ev: Event): void {
|
||||
const seconds = Number((ev.target as HTMLInputElement).value);
|
||||
this._configuration!.data.zha_options.consider_unavailable_battery =
|
||||
seconds;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
@@ -425,15 +419,7 @@ class ZHAOptionsPage extends LitElement {
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private async _updateConfiguration(
|
||||
ev: HASSDomCurrentTargetEvent<
|
||||
HTMLElement & {
|
||||
progress: boolean;
|
||||
actionSuccess: () => void;
|
||||
actionError: () => void;
|
||||
}
|
||||
>
|
||||
): Promise<void> {
|
||||
private async _updateConfiguration(ev: Event): Promise<void> {
|
||||
const button = ev.currentTarget as HTMLElement & {
|
||||
progress: boolean;
|
||||
actionSuccess: () => void;
|
||||
|
||||
+1
-4
@@ -2,7 +2,6 @@ import type { CSSResultGroup } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../../../common/dom/fire_event";
|
||||
import type { LocalizeKeys } from "../../../../../common/translations/localize";
|
||||
import "../../../../../components/ha-alert";
|
||||
import "../../../../../components/ha-button";
|
||||
@@ -479,9 +478,7 @@ class DialogZwaveCredentialUserEdit extends DirtyStateProviderMixin<CredentialFo
|
||||
}
|
||||
}
|
||||
|
||||
private _handleCredentialTypeChanged(
|
||||
ev: HASSDomCurrentTargetEvent<HaRadioGroup>
|
||||
): void {
|
||||
private _handleCredentialTypeChanged(ev: Event): void {
|
||||
this._credentialType = (ev.currentTarget as HaRadioGroup)
|
||||
.value as ZwaveCredentialType;
|
||||
// Switching types invalidates any data tied to the previous type's
|
||||
|
||||
@@ -2,13 +2,11 @@ import { mdiCloseCircle } from "@mdi/js";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/ha-button";
|
||||
import "../../../../../components/ha-select";
|
||||
import type { HaSelectSelectEvent } from "../../../../../components/ha-select";
|
||||
import "../../../../../components/ha-spinner";
|
||||
import "../../../../../components/input/ha-input";
|
||||
import type { HaInput } from "../../../../../components/input/ha-input";
|
||||
import {
|
||||
getZwaveNodeRawConfigParameter,
|
||||
setZwaveNodeRawConfigParameter,
|
||||
@@ -131,9 +129,9 @@ class ZWaveJSCustomParam extends LitElement {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
private _customParamNumberChanged(ev: HASSDomCurrentTargetEvent<HaInput>) {
|
||||
private _customParamNumberChanged(ev: Event) {
|
||||
this._customParamNumber = this._tryParseNumber(
|
||||
ev.currentTarget.value ?? ""
|
||||
(ev.target as HTMLInputElement).value
|
||||
);
|
||||
}
|
||||
|
||||
@@ -141,8 +139,8 @@ class ZWaveJSCustomParam extends LitElement {
|
||||
this._valueSize = this._tryParseNumber(ev.detail.value) ?? 1;
|
||||
}
|
||||
|
||||
private _customValueChanged(ev: HASSDomCurrentTargetEvent<HaInput>) {
|
||||
this._value = this._tryParseNumber(ev.currentTarget.value ?? "");
|
||||
private _customValueChanged(ev: Event) {
|
||||
this._value = this._tryParseNumber((ev.target as HTMLInputElement).value);
|
||||
}
|
||||
|
||||
private _customValueFormatChanged(ev: HaSelectSelectEvent) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../common/dom/fire_event";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-alert";
|
||||
@@ -284,9 +283,7 @@ export class SystemLogCard extends LitElement {
|
||||
fileDownload(signedUrl.path, logFileName);
|
||||
}
|
||||
|
||||
private _openLog(
|
||||
ev: HASSDomCurrentTargetEvent<HTMLElement & { logItem: LoggedError }>
|
||||
): void {
|
||||
private _openLog(ev: Event): void {
|
||||
const item = (ev.currentTarget as any).logItem;
|
||||
showSystemLogDetailDialog(this, { item });
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../common/dom/fire_event";
|
||||
import { isIPAddress } from "../../../common/string/is_ip_address";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-button";
|
||||
@@ -364,12 +363,12 @@ class ConfigUrlForm extends SubscribeMixin(LitElement) {
|
||||
);
|
||||
}
|
||||
|
||||
private _toggleCloud(ev: HASSDomCurrentTargetEvent<HaSwitch>) {
|
||||
private _toggleCloud(ev: Event) {
|
||||
this._cloudChecked = (ev.currentTarget as HaSwitch).checked;
|
||||
this._showCustomExternalUrl = !this._cloudChecked;
|
||||
}
|
||||
|
||||
private _toggleInternalAutomatic(ev: HASSDomCurrentTargetEvent<HaSwitch>) {
|
||||
private _toggleInternalAutomatic(ev: Event) {
|
||||
this._showCustomInternalUrl = !(ev.currentTarget as HaSwitch).checked;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,6 @@ import { mdiDeleteOutline, mdiMenuDown, mdiPlus, mdiWifi } from "@mdi/js";
|
||||
import { css, type CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { cache } from "lit/directives/cache";
|
||||
import type {
|
||||
HASSDomCurrentTargetEvent,
|
||||
HASSDomTargetEvent,
|
||||
} from "../../../common/dom/fire_event";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-card";
|
||||
@@ -634,9 +630,7 @@ export class HassioNetwork extends LitElement {
|
||||
this._interface = { ...this._interfaces[this._curTabIndex] };
|
||||
}
|
||||
|
||||
private _handleRadioValueChanged(
|
||||
ev: HASSDomCurrentTargetEvent<HaRadioGroup & { version: "ipv4" | "ipv6" }>
|
||||
): void {
|
||||
private _handleRadioValueChanged(ev: Event): void {
|
||||
const source = ev.currentTarget as HaRadioGroup;
|
||||
const value = source.value as "disabled" | "auto" | "static";
|
||||
const version = (source as any).version as "ipv4" | "ipv6";
|
||||
@@ -651,9 +645,7 @@ export class HassioNetwork extends LitElement {
|
||||
this.requestUpdate("_interface");
|
||||
}
|
||||
|
||||
private _handleRadioValueChangedAp(
|
||||
ev: HASSDomCurrentTargetEvent<HaRadioGroup>
|
||||
): void {
|
||||
private _handleRadioValueChangedAp(ev: Event): void {
|
||||
const source = ev.currentTarget as HaRadioGroup;
|
||||
const value = source.value as "open" | "wep" | "wpa-psk";
|
||||
this._wifiConfiguration!.auth = value;
|
||||
@@ -661,11 +653,7 @@ export class HassioNetwork extends LitElement {
|
||||
this.requestUpdate("_wifiConfiguration");
|
||||
}
|
||||
|
||||
private _handleInputValueChanged(
|
||||
ev: HASSDomTargetEvent<
|
||||
HaInput & { version: "ipv4" | "ipv6"; index: number }
|
||||
>
|
||||
): void {
|
||||
private _handleInputValueChanged(ev: Event): void {
|
||||
const source = ev.target as HaInput;
|
||||
const value = source.value;
|
||||
const version = (ev.target as any).version as "ipv4" | "ipv6";
|
||||
@@ -703,7 +691,7 @@ export class HassioNetwork extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _handleInputValueChangedWifi(ev: HASSDomTargetEvent<HaInput>): void {
|
||||
private _handleInputValueChangedWifi(ev: Event): void {
|
||||
const source = ev.target as HaInput;
|
||||
const value = source.value;
|
||||
const id = source.id;
|
||||
@@ -720,9 +708,7 @@ export class HassioNetwork extends LitElement {
|
||||
this._wifiConfiguration![id] = value;
|
||||
}
|
||||
|
||||
private _addAddress(
|
||||
ev: HASSDomTargetEvent<HTMLElement & { version: "ipv4" | "ipv6" }>
|
||||
): void {
|
||||
private _addAddress(ev: Event): void {
|
||||
const version = (ev.target as any).version as "ipv4" | "ipv6";
|
||||
this._interface![version]!.address!.push(
|
||||
version === "ipv4" ? "0.0.0.0/24" : "::/64"
|
||||
@@ -731,11 +717,7 @@ export class HassioNetwork extends LitElement {
|
||||
this.requestUpdate("_interface");
|
||||
}
|
||||
|
||||
private _removeAddress(
|
||||
ev: HASSDomTargetEvent<
|
||||
HTMLElement & { index: number; version: "ipv4" | "ipv6" }
|
||||
>
|
||||
): void {
|
||||
private _removeAddress(ev: Event): void {
|
||||
const source = ev.target as any;
|
||||
const index = source.index as number;
|
||||
const version = source.version as "ipv4" | "ipv6";
|
||||
@@ -770,11 +752,7 @@ export class HassioNetwork extends LitElement {
|
||||
this.requestUpdate("_interface");
|
||||
}
|
||||
|
||||
private _removeNameserver(
|
||||
ev: HASSDomTargetEvent<
|
||||
HTMLElement & { index: number; version: "ipv4" | "ipv6" }
|
||||
>
|
||||
): void {
|
||||
private _removeNameserver(ev: Event): void {
|
||||
const source = ev.target as any;
|
||||
const index = source.index as number;
|
||||
const version = source.version as "ipv4" | "ipv6";
|
||||
|
||||
@@ -11,7 +11,6 @@ import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { HASSDomCurrentTargetEvent } from "../../../../common/dom/fire_event";
|
||||
import { computeAreaName } from "../../../../common/entity/compute_area_name";
|
||||
import { computeDeviceName } from "../../../../common/entity/compute_device_name";
|
||||
import { computeEntityEntryName } from "../../../../common/entity/compute_entity_name";
|
||||
@@ -261,9 +260,7 @@ class HaPanelDevStateRenderer extends LitElement {
|
||||
return output;
|
||||
}
|
||||
|
||||
private _copyEntity = async (
|
||||
ev: HASSDomCurrentTargetEvent<HTMLElement & { entity: HassEntity }>
|
||||
) => {
|
||||
private _copyEntity = async (ev: Event) => {
|
||||
ev.preventDefault();
|
||||
const entity = (ev.currentTarget as HTMLElement & { entity: HassEntity })
|
||||
.entity;
|
||||
@@ -273,18 +270,14 @@ class HaPanelDevStateRenderer extends LitElement {
|
||||
});
|
||||
};
|
||||
|
||||
private _entityMoreInfo(
|
||||
ev: HASSDomCurrentTargetEvent<HTMLElement & { entity: HassEntity }>
|
||||
) {
|
||||
private _entityMoreInfo(ev: Event) {
|
||||
ev.preventDefault();
|
||||
const entity = (ev.currentTarget as HTMLElement & { entity: HassEntity })
|
||||
.entity;
|
||||
fireEvent(this, "hass-more-info", { entityId: entity.entity_id });
|
||||
}
|
||||
|
||||
private _entitySelected(
|
||||
ev: HASSDomCurrentTargetEvent<HTMLElement & { entity: HassEntity }>
|
||||
) {
|
||||
private _entitySelected(ev: Event) {
|
||||
ev.preventDefault();
|
||||
const entity = (ev.currentTarget as HTMLElement & { entity: HassEntity })
|
||||
.entity;
|
||||
|
||||
@@ -16,11 +16,7 @@ import { consume, type ContextType } from "@lit/context";
|
||||
import { css, type CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import type {
|
||||
HASSDomCurrentTargetEvent,
|
||||
HASSDomEvent,
|
||||
HASSDomTargetEvent,
|
||||
} from "../../../../common/dom/fire_event";
|
||||
import type { HASSDomEvent } from "../../../../common/dom/fire_event";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { computeAreaName } from "../../../../common/entity/compute_area_name";
|
||||
import {
|
||||
@@ -600,9 +596,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleSearchChange(
|
||||
ev: InputEvent & HASSDomTargetEvent<HaInputSearch>
|
||||
) {
|
||||
private _handleSearchChange(ev: InputEvent) {
|
||||
if (this.filter === (ev.target as HaInputSearch).value) {
|
||||
return;
|
||||
}
|
||||
@@ -712,9 +706,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
);
|
||||
}
|
||||
|
||||
private _showStatisticsAdjustSumDialog(
|
||||
ev: HASSDomCurrentTargetEvent<HTMLElement & { statistic: StatisticData }>
|
||||
) {
|
||||
private _showStatisticsAdjustSumDialog(ev: Event) {
|
||||
ev.stopPropagation();
|
||||
showStatisticsAdjustSumDialog(this, {
|
||||
statistic: (
|
||||
@@ -790,11 +782,7 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
|
||||
});
|
||||
};
|
||||
|
||||
private _fixIssue = async (
|
||||
ev: HASSDomCurrentTargetEvent<
|
||||
HTMLElement & { data: StatisticsValidationResult[] }
|
||||
>
|
||||
) => {
|
||||
private _fixIssue = async (ev: Event) => {
|
||||
const issues = (
|
||||
ev.currentTarget as HTMLElement & { data: StatisticsValidationResult[] }
|
||||
).data.sort(
|
||||
|
||||
@@ -9,7 +9,6 @@ import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import type { HASSDomTargetEvent } from "../../../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||
import type { LocalizeKeys } from "../../../../common/translations/localize";
|
||||
import { debounce } from "../../../../common/util/debounce";
|
||||
@@ -420,7 +419,7 @@ ${
|
||||
`;
|
||||
}
|
||||
|
||||
private _splitRepositioned(ev: HASSDomTargetEvent<HaSplitPanel>) {
|
||||
private _splitRepositioned(ev: Event) {
|
||||
this._splitPosition = (ev.target as HaSplitPanel).position;
|
||||
this._storeSplitPosition();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
formatCallyMonthYear,
|
||||
formatDate,
|
||||
formatDateWeekdayDay,
|
||||
formatDateShort,
|
||||
@@ -263,4 +264,43 @@ describe("formatDate", () => {
|
||||
).toBe("Sat");
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatCallyMonthYear", () => {
|
||||
// How cally hands out a calendar day: a Date anchored to UTC midnight
|
||||
const julyFirst = new Date(Date.UTC(2026, 6, 1));
|
||||
const januaryFirst = new Date(Date.UTC(2026, 0, 1));
|
||||
|
||||
// demoConfig.time_zone is America/Los_Angeles, so this resolves to a
|
||||
// negative UTC offset whatever zone the tests run in
|
||||
const locale = {
|
||||
language: "en",
|
||||
number_format: NumberFormat.language,
|
||||
time_format: TimeFormat.language,
|
||||
date_format: DateFormat.language,
|
||||
time_zone: TimeZone.server,
|
||||
first_weekday: FirstWeekday.language,
|
||||
};
|
||||
|
||||
it("Formats in UTC rather than the resolved time zone", () => {
|
||||
// A time zone aware formatter reads UTC midnight on the 1st as the
|
||||
// previous month, which desyncs the header from the calendar grid
|
||||
expect(formatDateMonthYear(julyFirst, locale, demoConfig)).toBe(
|
||||
"June 2026"
|
||||
);
|
||||
expect(formatCallyMonthYear(julyFirst, locale)).toBe("July 2026");
|
||||
});
|
||||
|
||||
it("Keeps the year on a January page", () => {
|
||||
expect(formatDateMonthYear(januaryFirst, locale, demoConfig)).toBe(
|
||||
"December 2025"
|
||||
);
|
||||
expect(formatCallyMonthYear(januaryFirst, locale)).toBe("January 2026");
|
||||
});
|
||||
|
||||
it("Orders month and year by locale", () => {
|
||||
expect(
|
||||
formatCallyMonthYear(julyFirst, { ...locale, language: "ja" })
|
||||
).toBe("2026年7月");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user