mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Add context providers and transform decorator (#15902)
This commit is contained in:
parent
4ba7e5cf0f
commit
74cfccaac7
@ -45,6 +45,7 @@
|
|||||||
"@fullcalendar/list": "6.1.5",
|
"@fullcalendar/list": "6.1.5",
|
||||||
"@fullcalendar/timegrid": "6.1.5",
|
"@fullcalendar/timegrid": "6.1.5",
|
||||||
"@lezer/highlight": "1.1.3",
|
"@lezer/highlight": "1.1.3",
|
||||||
|
"@lit-labs/context": "0.2.0",
|
||||||
"@lit-labs/motion": "1.0.3",
|
"@lit-labs/motion": "1.0.3",
|
||||||
"@lit-labs/virtualizer": "1.0.1",
|
"@lit-labs/virtualizer": "1.0.1",
|
||||||
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
|
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
|
||||||
|
111
src/common/decorators/transform.ts
Normal file
111
src/common/decorators/transform.ts
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import { PropertyDeclaration, PropertyValues, ReactiveElement } from "lit";
|
||||||
|
import { ClassElement } from "../../types";
|
||||||
|
import { shallowEqual } from "../util/shallow-equal";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform function type.
|
||||||
|
*/
|
||||||
|
export interface Transformer<T = any, V = any> {
|
||||||
|
(value: V): T;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReactiveTransformElement = ReactiveElement & {
|
||||||
|
_transformers: Map<PropertyKey, Transformer>;
|
||||||
|
_watching: Map<PropertyKey, Set<PropertyKey>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ReactiveElementClassWithTransformers = typeof ReactiveElement & {
|
||||||
|
prototype: ReactiveTransformElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies an tranformer callback that is run when the value of the decorated property, or any of the properties in the watching array, changes.
|
||||||
|
* The result of the tranformer is assigned to the decorated property.
|
||||||
|
* The tranformer receives the current as arguments.
|
||||||
|
*/
|
||||||
|
export const transform =
|
||||||
|
<T, V>(config: {
|
||||||
|
transformer: Transformer<T, V>;
|
||||||
|
watch?: PropertyKey[];
|
||||||
|
propertyOptions?: PropertyDeclaration;
|
||||||
|
}): any =>
|
||||||
|
(clsElement: ClassElement) => {
|
||||||
|
const key = String(clsElement.key);
|
||||||
|
return {
|
||||||
|
...clsElement,
|
||||||
|
kind: "method",
|
||||||
|
descriptor: {
|
||||||
|
set(this: ReactiveTransformElement, value: V) {
|
||||||
|
const oldValue = this[`__transform_${key}`];
|
||||||
|
const trnsformr: Transformer<T, V> | undefined =
|
||||||
|
this._transformers.get(key);
|
||||||
|
if (trnsformr) {
|
||||||
|
this[`__transform_${key}`] = trnsformr.call(this, value);
|
||||||
|
} else {
|
||||||
|
this[`__transform_${key}`] = value;
|
||||||
|
}
|
||||||
|
this[`__original_${key}`] = value;
|
||||||
|
this.requestUpdate(key, oldValue);
|
||||||
|
},
|
||||||
|
get(): T {
|
||||||
|
return this[`__transform_${key}`];
|
||||||
|
},
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
},
|
||||||
|
finisher(cls: ReactiveElementClassWithTransformers) {
|
||||||
|
// if we haven't wrapped `willUpdate` in this class, do so
|
||||||
|
if (!cls.prototype._transformers) {
|
||||||
|
cls.prototype._transformers = new Map<PropertyKey, Transformer>();
|
||||||
|
cls.prototype._watching = new Map<PropertyKey, Set<PropertyKey>>();
|
||||||
|
// @ts-ignore
|
||||||
|
const userWillUpdate = cls.prototype.willUpdate;
|
||||||
|
// @ts-ignore
|
||||||
|
cls.prototype.willUpdate = function (
|
||||||
|
this: ReactiveTransformElement,
|
||||||
|
changedProperties: PropertyValues
|
||||||
|
) {
|
||||||
|
userWillUpdate.call(this, changedProperties);
|
||||||
|
const keys = new Set<PropertyKey>();
|
||||||
|
changedProperties.forEach((_v, k) => {
|
||||||
|
const watchers = this._watching;
|
||||||
|
const ks: Set<PropertyKey> | undefined = watchers.get(k);
|
||||||
|
if (ks !== undefined) {
|
||||||
|
ks.forEach((wk) => keys.add(wk));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
keys.forEach((k) => {
|
||||||
|
// trigger setter
|
||||||
|
this[k] = this[`__original_${String(k)}`];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// clone any existing observers (superclasses)
|
||||||
|
// eslint-disable-next-line no-prototype-builtins
|
||||||
|
} else if (!cls.prototype.hasOwnProperty("_transformers")) {
|
||||||
|
const tranformers = cls.prototype._transformers;
|
||||||
|
cls.prototype._transformers = new Map();
|
||||||
|
tranformers.forEach((v: any, k: PropertyKey) =>
|
||||||
|
cls.prototype._transformers.set(k, v)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// set this method
|
||||||
|
cls.prototype._transformers.set(clsElement.key, config.transformer);
|
||||||
|
if (config.watch) {
|
||||||
|
// store watchers
|
||||||
|
config.watch.forEach((k) => {
|
||||||
|
let curWatch = cls.prototype._watching.get(k);
|
||||||
|
if (!curWatch) {
|
||||||
|
curWatch = new Set();
|
||||||
|
cls.prototype._watching.set(k, curWatch);
|
||||||
|
}
|
||||||
|
curWatch.add(clsElement.key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
cls.createProperty(clsElement.key, {
|
||||||
|
noAccessor: true,
|
||||||
|
hasChanged: (v: any, o: any) => !shallowEqual(v, o),
|
||||||
|
...config.propertyOptions,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
108
src/common/util/shallow-equal.ts
Normal file
108
src/common/util/shallow-equal.ts
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
* Compares two values for shallow equality, only 1 level deep.
|
||||||
|
*/
|
||||||
|
export const shallowEqual = (a: any, b: any): boolean => {
|
||||||
|
if (a === b) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a && b && typeof a === "object" && typeof b === "object") {
|
||||||
|
if (a.constructor !== b.constructor) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let i: number | [any, any];
|
||||||
|
let length: number;
|
||||||
|
if (Array.isArray(a)) {
|
||||||
|
length = a.length;
|
||||||
|
if (length !== b.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (i = length; i-- !== 0; ) {
|
||||||
|
if (a[i] !== b[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a instanceof Map && b instanceof Map) {
|
||||||
|
if (a.size !== b.size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (i of a.entries()) {
|
||||||
|
if (!b.has(i[0])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i of a.entries()) {
|
||||||
|
if (i[1] !== b.get(i[0])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a instanceof Set && b instanceof Set) {
|
||||||
|
if (a.size !== b.size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (i of a.entries()) {
|
||||||
|
if (!b.has(i[0])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
|
||||||
|
// @ts-ignore
|
||||||
|
length = a.length;
|
||||||
|
// @ts-ignore
|
||||||
|
if (length !== b.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (i = length; i-- !== 0; ) {
|
||||||
|
if (a[i] !== b[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.constructor === RegExp) {
|
||||||
|
return a.source === b.source && a.flags === b.flags;
|
||||||
|
}
|
||||||
|
if (a.valueOf !== Object.prototype.valueOf) {
|
||||||
|
return a.valueOf() === b.valueOf();
|
||||||
|
}
|
||||||
|
if (a.toString !== Object.prototype.toString) {
|
||||||
|
return a.toString() === b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
const keys = Object.keys(a);
|
||||||
|
length = keys.length;
|
||||||
|
if (length !== Object.keys(b).length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (i = length; i-- !== 0; ) {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = length; i-- !== 0; ) {
|
||||||
|
const key = keys[i];
|
||||||
|
|
||||||
|
if (a[key] !== b[key]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// true if both NaN, false otherwise
|
||||||
|
// eslint-disable-next-line no-self-compare
|
||||||
|
return a !== a && b !== b;
|
||||||
|
};
|
24
src/data/context.ts
Normal file
24
src/data/context.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { createContext } from "@lit-labs/context";
|
||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
import { EntityRegistryEntry } from "./entity_registry";
|
||||||
|
|
||||||
|
export const statesContext = createContext<HomeAssistant["states"]>("states");
|
||||||
|
export const entitiesContext =
|
||||||
|
createContext<HomeAssistant["entities"]>("entities");
|
||||||
|
export const devicesContext =
|
||||||
|
createContext<HomeAssistant["devices"]>("devices");
|
||||||
|
export const areasContext = createContext<HomeAssistant["areas"]>("areas");
|
||||||
|
export const localizeContext =
|
||||||
|
createContext<HomeAssistant["localize"]>("localize");
|
||||||
|
export const localeContext = createContext<HomeAssistant["locale"]>("locale");
|
||||||
|
export const configContext = createContext<HomeAssistant["config"]>("config");
|
||||||
|
export const themesContext = createContext<HomeAssistant["themes"]>("themes");
|
||||||
|
export const selectedThemeContext =
|
||||||
|
createContext<HomeAssistant["selectedTheme"]>("selectedTheme");
|
||||||
|
export const userContext = createContext<HomeAssistant["user"]>("user");
|
||||||
|
export const userDataContext =
|
||||||
|
createContext<HomeAssistant["userData"]>("userData");
|
||||||
|
export const panelsContext = createContext<HomeAssistant["panels"]>("panels");
|
||||||
|
|
||||||
|
export const extendedEntitiesContext =
|
||||||
|
createContext<EntityRegistryEntry[]>("extendedEntities");
|
@ -181,6 +181,10 @@ export class HomeAssistantMain extends LitElement {
|
|||||||
this.drawer.close();
|
this.drawer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!changedProps.has("hass")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||||
|
|
||||||
// Make app-drawer adjust to a potential LTR/RTL change
|
// Make app-drawer adjust to a potential LTR/RTL change
|
||||||
|
@ -1,25 +1,21 @@
|
|||||||
|
import { consume } from "@lit-labs/context";
|
||||||
import "@material/mwc-ripple";
|
import "@material/mwc-ripple";
|
||||||
import type { Ripple } from "@material/mwc-ripple";
|
import type { Ripple } from "@material/mwc-ripple";
|
||||||
import { RippleHandlers } from "@material/mwc-ripple/ripple-handlers";
|
import { RippleHandlers } from "@material/mwc-ripple/ripple-handlers";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntities, HassEntity } from "home-assistant-js-websocket";
|
||||||
import {
|
import {
|
||||||
css,
|
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
html,
|
|
||||||
LitElement,
|
LitElement,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
|
css,
|
||||||
|
html,
|
||||||
nothing,
|
nothing,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import {
|
import { customElement, eventOptions, queryAsync, state } from "lit/decorators";
|
||||||
customElement,
|
|
||||||
eventOptions,
|
|
||||||
property,
|
|
||||||
queryAsync,
|
|
||||||
state,
|
|
||||||
} from "lit/decorators";
|
|
||||||
import { ifDefined } from "lit/directives/if-defined";
|
import { ifDefined } from "lit/directives/if-defined";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
import { styleMap } from "lit/directives/style-map";
|
||||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||||
|
import { transform } from "../../../common/decorators/transform";
|
||||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||||
@ -30,6 +26,13 @@ import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
|||||||
import { iconColorCSS } from "../../../common/style/icon_color_css";
|
import { iconColorCSS } from "../../../common/style/icon_color_css";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import { HVAC_ACTION_TO_MODE } from "../../../data/climate";
|
import { HVAC_ACTION_TO_MODE } from "../../../data/climate";
|
||||||
|
import {
|
||||||
|
entitiesContext,
|
||||||
|
localeContext,
|
||||||
|
localizeContext,
|
||||||
|
statesContext,
|
||||||
|
themesContext,
|
||||||
|
} from "../../../data/context";
|
||||||
import { LightEntity } from "../../../data/light";
|
import { LightEntity } from "../../../data/light";
|
||||||
import { ActionHandlerEvent } from "../../../data/lovelace";
|
import { ActionHandlerEvent } from "../../../data/lovelace";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
@ -40,6 +43,9 @@ import { hasAction } from "../common/has-action";
|
|||||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||||
import { ButtonCardConfig } from "./types";
|
import { ButtonCardConfig } from "./types";
|
||||||
|
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||||
|
import { FrontendLocaleData } from "../../../data/translation";
|
||||||
|
import { Themes } from "../../../data/ws-themes";
|
||||||
|
|
||||||
@customElement("hui-button-card")
|
@customElement("hui-button-card")
|
||||||
export class HuiButtonCard extends LitElement implements LovelaceCard {
|
export class HuiButtonCard extends LitElement implements LovelaceCard {
|
||||||
@ -71,10 +77,39 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
public hass!: HomeAssistant;
|
||||||
|
|
||||||
@state() private _config?: ButtonCardConfig;
|
@state() private _config?: ButtonCardConfig;
|
||||||
|
|
||||||
|
@consume<any>({ context: statesContext, subscribe: true })
|
||||||
|
@transform({
|
||||||
|
transformer: function (this: HuiButtonCard, value: HassEntities) {
|
||||||
|
return this._config?.entity ? value[this._config?.entity] : undefined;
|
||||||
|
},
|
||||||
|
watch: ["_config"],
|
||||||
|
})
|
||||||
|
_stateObj?: HassEntity;
|
||||||
|
|
||||||
|
@consume({ context: themesContext, subscribe: true })
|
||||||
|
_themes!: Themes;
|
||||||
|
|
||||||
|
@consume({ context: localizeContext, subscribe: true })
|
||||||
|
_localize!: LocalizeFunc;
|
||||||
|
|
||||||
|
@consume({ context: localeContext, subscribe: true })
|
||||||
|
_locale!: FrontendLocaleData;
|
||||||
|
|
||||||
|
@consume({ context: entitiesContext, subscribe: true })
|
||||||
|
@transform<HomeAssistant["entities"], HomeAssistant["entities"]>({
|
||||||
|
transformer: function (this: HuiButtonCard, value) {
|
||||||
|
return this._config?.entity
|
||||||
|
? { [this._config?.entity]: value[this._config?.entity] }
|
||||||
|
: {};
|
||||||
|
},
|
||||||
|
watch: ["_config"],
|
||||||
|
})
|
||||||
|
_entities!: HomeAssistant["entities"];
|
||||||
|
|
||||||
@queryAsync("mwc-ripple") private _ripple!: Promise<Ripple | null>;
|
@queryAsync("mwc-ripple") private _ripple!: Promise<Ripple | null>;
|
||||||
|
|
||||||
@state() private _shouldRenderRipple = false;
|
@state() private _shouldRenderRipple = false;
|
||||||
@ -114,35 +149,11 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
|
||||||
if (changedProps.has("_config")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!oldHass ||
|
|
||||||
oldHass.themes !== this.hass!.themes ||
|
|
||||||
oldHass.locale !== this.hass!.locale
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
Boolean(this._config!.entity) &&
|
|
||||||
oldHass.states[this._config!.entity!] !==
|
|
||||||
this.hass!.states[this._config!.entity!]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
if (!this._config || !this.hass) {
|
if (!this._config) {
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
const stateObj = this._config.entity
|
const stateObj = this._stateObj;
|
||||||
? this.hass.states[this._config.entity]
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
if (this._config.entity && !stateObj) {
|
if (this._config.entity && !stateObj) {
|
||||||
return html`
|
return html`
|
||||||
@ -207,10 +218,10 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
|||||||
${this._config.show_state && stateObj
|
${this._config.show_state && stateObj
|
||||||
? html`<span class="state">
|
? html`<span class="state">
|
||||||
${computeStateDisplay(
|
${computeStateDisplay(
|
||||||
this.hass.localize,
|
this._localize,
|
||||||
stateObj,
|
stateObj,
|
||||||
this.hass.locale,
|
this._locale,
|
||||||
this.hass.entities
|
this._entities
|
||||||
)}
|
)}
|
||||||
</span>`
|
</span>`
|
||||||
: ""}
|
: ""}
|
||||||
@ -221,21 +232,23 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
protected updated(changedProps: PropertyValues): void {
|
protected updated(changedProps: PropertyValues): void {
|
||||||
super.updated(changedProps);
|
super.updated(changedProps);
|
||||||
if (!this._config || !this.hass) {
|
if (!this._config) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
const oldThemes = changedProps.get("_themes") as
|
||||||
|
| HomeAssistant["themes"]
|
||||||
|
| undefined;
|
||||||
const oldConfig = changedProps.get("_config") as
|
const oldConfig = changedProps.get("_config") as
|
||||||
| ButtonCardConfig
|
| ButtonCardConfig
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!oldHass ||
|
!oldThemes ||
|
||||||
!oldConfig ||
|
!oldConfig ||
|
||||||
oldHass.themes !== this.hass.themes ||
|
oldThemes !== this._themes ||
|
||||||
oldConfig.theme !== this._config.theme
|
oldConfig.theme !== this._config.theme
|
||||||
) {
|
) {
|
||||||
applyThemesOnElement(this, this.hass.themes, this._config.theme);
|
applyThemesOnElement(this, this._themes, this._config.theme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
97
src/state/context-mixin.ts
Normal file
97
src/state/context-mixin.ts
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import { ContextProvider } from "@lit-labs/context";
|
||||||
|
import {
|
||||||
|
areasContext,
|
||||||
|
configContext,
|
||||||
|
devicesContext,
|
||||||
|
entitiesContext,
|
||||||
|
localeContext,
|
||||||
|
localizeContext,
|
||||||
|
panelsContext,
|
||||||
|
selectedThemeContext,
|
||||||
|
statesContext,
|
||||||
|
themesContext,
|
||||||
|
userContext,
|
||||||
|
userDataContext,
|
||||||
|
} from "../data/context";
|
||||||
|
import { Constructor, HomeAssistant } from "../types";
|
||||||
|
import { HassBaseEl } from "./hass-base-mixin";
|
||||||
|
|
||||||
|
export const contextMixin = <T extends Constructor<HassBaseEl>>(
|
||||||
|
superClass: T
|
||||||
|
) =>
|
||||||
|
class extends superClass {
|
||||||
|
private __contextProviders: Record<
|
||||||
|
string,
|
||||||
|
ContextProvider<any> | undefined
|
||||||
|
> = {
|
||||||
|
states: new ContextProvider(
|
||||||
|
this,
|
||||||
|
statesContext,
|
||||||
|
this.hass ? this.hass.states : this._pendingHass.states
|
||||||
|
),
|
||||||
|
entities: new ContextProvider(
|
||||||
|
this,
|
||||||
|
entitiesContext,
|
||||||
|
this.hass ? this.hass.entities : this._pendingHass.entities
|
||||||
|
),
|
||||||
|
devices: new ContextProvider(
|
||||||
|
this,
|
||||||
|
devicesContext,
|
||||||
|
this.hass ? this.hass.devices : this._pendingHass.devices
|
||||||
|
),
|
||||||
|
areas: new ContextProvider(
|
||||||
|
this,
|
||||||
|
areasContext,
|
||||||
|
this.hass ? this.hass.areas : this._pendingHass.areas
|
||||||
|
),
|
||||||
|
localize: new ContextProvider(
|
||||||
|
this,
|
||||||
|
localizeContext,
|
||||||
|
this.hass ? this.hass.localize : this._pendingHass.localize
|
||||||
|
),
|
||||||
|
locale: new ContextProvider(
|
||||||
|
this,
|
||||||
|
localeContext,
|
||||||
|
this.hass ? this.hass.locale : this._pendingHass.locale
|
||||||
|
),
|
||||||
|
config: new ContextProvider(
|
||||||
|
this,
|
||||||
|
configContext,
|
||||||
|
this.hass ? this.hass.config : this._pendingHass.config
|
||||||
|
),
|
||||||
|
themes: new ContextProvider(
|
||||||
|
this,
|
||||||
|
themesContext,
|
||||||
|
this.hass ? this.hass.themes : this._pendingHass.themes
|
||||||
|
),
|
||||||
|
selectedTheme: new ContextProvider(
|
||||||
|
this,
|
||||||
|
selectedThemeContext,
|
||||||
|
this.hass ? this.hass.selectedTheme : this._pendingHass.selectedTheme
|
||||||
|
),
|
||||||
|
user: new ContextProvider(
|
||||||
|
this,
|
||||||
|
userContext,
|
||||||
|
this.hass ? this.hass.user : this._pendingHass.user
|
||||||
|
),
|
||||||
|
userData: new ContextProvider(
|
||||||
|
this,
|
||||||
|
userDataContext,
|
||||||
|
this.hass ? this.hass.userData : this._pendingHass.userData
|
||||||
|
),
|
||||||
|
panels: new ContextProvider(
|
||||||
|
this,
|
||||||
|
panelsContext,
|
||||||
|
this.hass ? this.hass.panels : this._pendingHass.panels
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
protected _updateHass(obj: Partial<HomeAssistant>) {
|
||||||
|
super._updateHass(obj);
|
||||||
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
|
if (key in this.__contextProviders) {
|
||||||
|
this.__contextProviders[key]!.setValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -6,6 +6,7 @@ import DisconnectToastMixin from "./disconnect-toast-mixin";
|
|||||||
import { hapticMixin } from "./haptic-mixin";
|
import { hapticMixin } from "./haptic-mixin";
|
||||||
import { HassBaseEl } from "./hass-base-mixin";
|
import { HassBaseEl } from "./hass-base-mixin";
|
||||||
import { loggingMixin } from "./logging-mixin";
|
import { loggingMixin } from "./logging-mixin";
|
||||||
|
import { contextMixin } from "./context-mixin";
|
||||||
import MoreInfoMixin from "./more-info-mixin";
|
import MoreInfoMixin from "./more-info-mixin";
|
||||||
import NotificationMixin from "./notification-mixin";
|
import NotificationMixin from "./notification-mixin";
|
||||||
import { panelTitleMixin } from "./panel-title-mixin";
|
import { panelTitleMixin } from "./panel-title-mixin";
|
||||||
@ -31,4 +32,5 @@ export class HassElement extends ext(HassBaseEl, [
|
|||||||
hapticMixin,
|
hapticMixin,
|
||||||
panelTitleMixin,
|
panelTitleMixin,
|
||||||
loggingMixin,
|
loggingMixin,
|
||||||
|
contextMixin,
|
||||||
]) {}
|
]) {}
|
||||||
|
13
yarn.lock
13
yarn.lock
@ -1955,6 +1955,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@lit-labs/context@npm:0.2.0":
|
||||||
|
version: 0.2.0
|
||||||
|
resolution: "@lit-labs/context@npm:0.2.0"
|
||||||
|
dependencies:
|
||||||
|
"@lit/reactive-element": ^1.5.0
|
||||||
|
lit: ^2.5.0
|
||||||
|
checksum: 0b3d803ba81683d9650ba384e5f138656ecd52d6a54448535e867e0a0ba0cb23e4526ec52e82ed657e9c3598a103c0e8b164bfe927222467e349fb070c770af3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@lit-labs/motion@npm:1.0.3":
|
"@lit-labs/motion@npm:1.0.3":
|
||||||
version: 1.0.3
|
version: 1.0.3
|
||||||
resolution: "@lit-labs/motion@npm:1.0.3"
|
resolution: "@lit-labs/motion@npm:1.0.3"
|
||||||
@ -1982,7 +1992,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@lit/reactive-element@npm:^1.3.0, @lit/reactive-element@npm:^1.6.0":
|
"@lit/reactive-element@npm:^1.3.0, @lit/reactive-element@npm:^1.5.0, @lit/reactive-element@npm:^1.6.0":
|
||||||
version: 1.6.1
|
version: 1.6.1
|
||||||
resolution: "@lit/reactive-element@npm:1.6.1"
|
resolution: "@lit/reactive-element@npm:1.6.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -9416,6 +9426,7 @@ __metadata:
|
|||||||
"@fullcalendar/timegrid": 6.1.5
|
"@fullcalendar/timegrid": 6.1.5
|
||||||
"@koa/cors": 4.0.0
|
"@koa/cors": 4.0.0
|
||||||
"@lezer/highlight": 1.1.3
|
"@lezer/highlight": 1.1.3
|
||||||
|
"@lit-labs/context": 0.2.0
|
||||||
"@lit-labs/motion": 1.0.3
|
"@lit-labs/motion": 1.0.3
|
||||||
"@lit-labs/virtualizer": 1.0.1
|
"@lit-labs/virtualizer": 1.0.1
|
||||||
"@material/chips": =14.0.0-canary.53b3cad2f.0
|
"@material/chips": =14.0.0-canary.53b3cad2f.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user