mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-22 10:32:57 +00:00
Compare commits
3 Commits
dev
...
refactor/c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
545fac605e | ||
|
|
b0057042f3 | ||
|
|
6a70c81dc4 |
93
src/common/decorators/consume-context-entry.ts
Normal file
93
src/common/decorators/consume-context-entry.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntities, HassEntity } from "home-assistant-js-websocket";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import { entitiesContext, statesContext } from "../../data/context";
|
||||
import type { EntityRegistryDisplayEntry } from "../../data/entity/entity_registry";
|
||||
import { transform } from "./transform";
|
||||
|
||||
interface ConsumeEntryConfig {
|
||||
entityIdPath: readonly string[];
|
||||
}
|
||||
|
||||
const resolveAtPath = (host: unknown, path: readonly string[]) => {
|
||||
let cur: any = host;
|
||||
for (const seg of path) {
|
||||
if (cur == null) return undefined;
|
||||
cur = cur[seg];
|
||||
}
|
||||
return cur;
|
||||
};
|
||||
|
||||
const composeDecorator = <T, V>(
|
||||
context: Parameters<typeof consume>[0]["context"],
|
||||
watchKey: string | undefined,
|
||||
select: (this: unknown, value: T) => V | undefined
|
||||
) => {
|
||||
const transformDec = transform<T, V | undefined>({
|
||||
transformer: function (this: unknown, value) {
|
||||
return select.call(this, value);
|
||||
},
|
||||
watch: watchKey ? [watchKey] : [],
|
||||
});
|
||||
const consumeDec = consume<any>({ context, subscribe: true });
|
||||
return (proto: any, propertyKey: string) => {
|
||||
transformDec(proto, propertyKey);
|
||||
consumeDec(proto, propertyKey);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Consumes `statesContext` and narrows it to the `HassEntity` for the entity
|
||||
* ID found at `entityIdPath` on the host (e.g. `["_config", "entity"]`).
|
||||
*
|
||||
* The first path segment is watched on the host — changes to it re-run the
|
||||
* lookup. Deeper segments are traversed at lookup time and short-circuit on
|
||||
* nullish values.
|
||||
*/
|
||||
export const consumeEntityState = (config: ConsumeEntryConfig) =>
|
||||
composeDecorator<HassEntities, HassEntity>(
|
||||
statesContext,
|
||||
config.entityIdPath[0],
|
||||
function (states) {
|
||||
const id = resolveAtPath(this, config.entityIdPath);
|
||||
return typeof id === "string" ? states?.[id] : undefined;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Like {@link consumeEntityState} but for an array of entity IDs at
|
||||
* `entityIdPath`. Resolves to a `HassEntity[]` containing one entry per
|
||||
* currently-available entity (missing entities and non-string IDs are
|
||||
* filtered out; original order is preserved).
|
||||
*/
|
||||
export const consumeEntityStates = (config: ConsumeEntryConfig) =>
|
||||
composeDecorator<HassEntities, HassEntity[]>(
|
||||
statesContext,
|
||||
config.entityIdPath[0],
|
||||
function (states) {
|
||||
const ids = resolveAtPath(this, config.entityIdPath);
|
||||
if (!Array.isArray(ids) || !states) return undefined;
|
||||
const result: HassEntity[] = [];
|
||||
for (const id of ids) {
|
||||
if (typeof id !== "string") continue;
|
||||
const state = states[id];
|
||||
if (state !== undefined) result.push(state);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Consumes `entitiesContext` and narrows it to the
|
||||
* `EntityRegistryDisplayEntry` for the entity ID found at `entityIdPath` on
|
||||
* the host. See {@link consumeEntityState} for semantics.
|
||||
*/
|
||||
export const consumeEntityRegistryEntry = (config: ConsumeEntryConfig) =>
|
||||
composeDecorator<HomeAssistant["entities"], EntityRegistryDisplayEntry>(
|
||||
entitiesContext,
|
||||
config.entityIdPath[0],
|
||||
function (entities) {
|
||||
const id = resolveAtPath(this, config.entityIdPath);
|
||||
return typeof id === "string" ? entities?.[id] : undefined;
|
||||
}
|
||||
);
|
||||
@@ -1,5 +1,5 @@
|
||||
import { consume, type ContextType } from "@lit/context";
|
||||
import type { HassEntities, HassEntity } from "home-assistant-js-websocket";
|
||||
import { consume } from "@lit/context";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, state } from "lit/decorators";
|
||||
@@ -7,6 +7,10 @@ import { ifDefined } from "lit/directives/if-defined";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||
import {
|
||||
consumeEntityRegistryEntry,
|
||||
consumeEntityState,
|
||||
} from "../../../common/decorators/consume-context-entry";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
@@ -22,11 +26,7 @@ import { iconColorCSS } from "../../../common/style/icon_color_css";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-ripple";
|
||||
import { CLIMATE_HVAC_ACTION_TO_MODE } from "../../../data/climate";
|
||||
import {
|
||||
entitiesContext,
|
||||
statesContext,
|
||||
uiContext,
|
||||
} from "../../../data/context";
|
||||
import { uiContext } from "../../../data/context";
|
||||
import type { EntityRegistryDisplayEntry } from "../../../data/entity/entity_registry";
|
||||
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
|
||||
import type { Themes } from "../../../data/ws-themes";
|
||||
@@ -94,13 +94,7 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
||||
@state() private _config?: ButtonCardConfig;
|
||||
|
||||
@state()
|
||||
@consume<any>({ context: statesContext, subscribe: true })
|
||||
@transform({
|
||||
transformer: function (this: HuiButtonCard, value: HassEntities) {
|
||||
return this._config?.entity ? value?.[this._config?.entity] : undefined;
|
||||
},
|
||||
watch: ["_config"],
|
||||
})
|
||||
@consumeEntityState({ entityIdPath: ["_config", "entity"] })
|
||||
private _stateObj?: HassEntity;
|
||||
|
||||
@state()
|
||||
@@ -111,13 +105,7 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
||||
private _themes!: Themes;
|
||||
|
||||
@state()
|
||||
@consume<any>({ context: entitiesContext, subscribe: true })
|
||||
@transform<ContextType<typeof entitiesContext>, EntityRegistryDisplayEntry>({
|
||||
transformer: function (this: HuiButtonCard, value) {
|
||||
return this._config?.entity ? value?.[this._config?.entity] : undefined;
|
||||
},
|
||||
watch: ["_config"],
|
||||
})
|
||||
@consumeEntityRegistryEntry({ entityIdPath: ["_config", "entity"] })
|
||||
_entity?: EntityRegistryDisplayEntry;
|
||||
|
||||
public getCardSize(): number {
|
||||
|
||||
Reference in New Issue
Block a user