Use resize controller for weather card

This commit is contained in:
Paul Bottein 2024-02-15 09:59:12 +01:00
parent 8136cc8008
commit af6342b917
No known key found for this signature in database
1 changed files with 38 additions and 73 deletions

View File

@ -1,3 +1,4 @@
import { ResizeController } from "@lit-labs/observers/resize-controller";
import { import {
CSSResultGroup, CSSResultGroup,
LitElement, LitElement,
@ -14,7 +15,6 @@ import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_elemen
import { computeStateName } from "../../../common/entity/compute_state_name"; import { computeStateName } from "../../../common/entity/compute_state_name";
import { isValidEntityId } from "../../../common/entity/valid_entity_id"; import { isValidEntityId } from "../../../common/entity/valid_entity_id";
import { formatNumber } from "../../../common/number/format_number"; import { formatNumber } from "../../../common/number/format_number";
import { debounce } from "../../../common/util/debounce";
import "../../../components/ha-card"; import "../../../components/ha-card";
import "../../../components/ha-svg-icon"; import "../../../components/ha-svg-icon";
import { UNAVAILABLE } from "../../../data/entity"; import { UNAVAILABLE } from "../../../data/entity";
@ -31,7 +31,6 @@ import {
weatherAttrIcons, weatherAttrIcons,
weatherSVGStyles, weatherSVGStyles,
} from "../../../data/weather"; } from "../../../data/weather";
import { loadPolyfillIfNeeded } from "../../../resources/resize-observer.polyfill";
import type { HomeAssistant } from "../../../types"; import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive"; import { actionHandler } from "../common/directives/action-handler-directive";
import { findEntities } from "../common/find-entities"; import { findEntities } from "../common/find-entities";
@ -75,10 +74,25 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
@state() private _subscribed?: Promise<() => void>; @state() private _subscribed?: Promise<() => void>;
// @todo Consider reworking to eliminate need for attribute since it is manipulated internally private _sizeController = new ResizeController(this, {
@property({ type: Boolean, reflect: true }) public veryVeryNarrow = false; callback: (entries) => {
const width = entries[0]?.contentRect.width;
if (width < 245) {
return "very-very-narrow";
}
if (width < 300) {
return "very-narrow";
}
if (width < 375) {
return "narrow";
}
return "regular";
},
});
private _resizeObserver?: ResizeObserver; protected firstUpdated(): void {
this._sizeController.observe(this.shadowRoot!.querySelector("ha-card")!);
}
private _needForecastSubscription() { private _needForecastSubscription() {
return ( return (
@ -119,14 +133,10 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
if (this.hasUpdated && this._config && this.hass) { if (this.hasUpdated && this._config && this.hass) {
this._subscribeForecastEvents(); this._subscribeForecastEvents();
} }
this.updateComplete.then(() => this._attachObserver());
} }
public disconnectedCallback(): void { public disconnectedCallback(): void {
super.disconnectedCallback(); super.disconnectedCallback();
if (this._resizeObserver) {
this._resizeObserver.disconnect();
}
this._unsubscribeForecastEvents(); this._unsubscribeForecastEvents();
} }
@ -160,16 +170,6 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
); );
} }
public willUpdate(): void {
if (!this.hasUpdated) {
this._measureCard();
}
}
protected firstUpdated(): void {
this._attachObserver();
}
protected updated(changedProps: PropertyValues): void { protected updated(changedProps: PropertyValues): void {
super.updated(changedProps); super.updated(changedProps);
if (!this._config || !this.hass) { if (!this._config || !this.hass) {
@ -227,7 +227,10 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
); );
const forecast = const forecast =
this._config?.show_forecast !== false && forecastData?.forecast?.length this._config?.show_forecast !== false && forecastData?.forecast?.length
? forecastData.forecast.slice(0, this.veryVeryNarrow ? 3 : 5) ? forecastData.forecast.slice(
0,
this._sizeController.value === "very-very-narrow" ? 3 : 5
)
: undefined; : undefined;
const weather = !forecast || this._config?.show_current !== false; const weather = !forecast || this._config?.show_current !== false;
@ -239,6 +242,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
return html` return html`
<ha-card <ha-card
class=${ifDefined(this._sizeController.value)}
@action=${this._handleAction} @action=${this._handleAction}
.actionHandler=${actionHandler({ .actionHandler=${actionHandler({
hasHold: hasAction(this._config!.hold_action), hasHold: hasAction(this._config!.hold_action),
@ -417,45 +421,6 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
handleAction(this, this.hass!, this._config!, ev.detail.action!); handleAction(this, this.hass!, this._config!, ev.detail.action!);
} }
private async _attachObserver(): Promise<void> {
if (!this._resizeObserver) {
await loadPolyfillIfNeeded();
this._resizeObserver = new ResizeObserver(
debounce(() => this._measureCard(), 250, false)
);
}
const card = this.shadowRoot!.querySelector("ha-card");
// If we show an error or warning there is no ha-card
if (!card) {
return;
}
this._resizeObserver.observe(card);
}
private _measureCard() {
if (!this.isConnected) {
return;
}
const card = this.shadowRoot!.querySelector("ha-card");
// If we show an error or warning there is no ha-card
if (!card) {
return;
}
if (card.offsetWidth < 375) {
this.setAttribute("narrow", "");
} else {
this.removeAttribute("narrow");
}
if (card.offsetWidth < 300) {
this.setAttribute("verynarrow", "");
} else {
this.removeAttribute("verynarrow");
}
this.veryVeryNarrow = card.offsetWidth < 245;
}
private _showValue(item?: any): boolean { private _showValue(item?: any): boolean {
return typeof item !== "undefined" && item !== null; return typeof item !== "undefined" && item !== null;
} }
@ -614,48 +579,48 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
/* ============= NARROW ============= */ /* ============= NARROW ============= */
:host([narrow]) .icon-image { [class*="narrow"] .icon-image {
min-width: 52px; min-width: 52px;
} }
:host([narrow]) .weather-image { [class*="narrow"] .weather-image {
flex: 0 0 52px; flex: 0 0 52px;
width: 52px; width: 52px;
} }
:host([narrow]) .icon-image .weather-icon { [class*="narrow"] .icon-image .weather-icon {
--mdc-icon-size: 52px; --mdc-icon-size: 52px;
} }
:host([narrow]) .state, [class*="narrow"] .state,
:host([narrow]) .temp-attribute .temp { [class*="narrow"] .temp-attribute .temp {
font-size: 22px; font-size: 22px;
} }
:host([narrow]) .temp-attribute .temp { [class*="narrow"] .temp-attribute .temp {
margin-right: 16px; margin-right: 16px;
margin-inline-end: 16px; margin-inline-end: 16px;
margin-inline-start: initial; margin-inline-start: initial;
} }
:host([narrow]) .temp span { [class*="narrow"] .temp span {
top: 1px; top: 1px;
font-size: 16px; font-size: 16px;
} }
/* ============= VERY NARROW ============= */ /* ============= VERY NARROW ============= */
:host([veryNarrow]) .name, [class*="very-narrow"] .name,
:host([veryNarrow]) .attribute { [class*="very-narrow"] .attribute {
display: none; display: none;
} }
:host([veryNarrow]) .info { [class*="very-narrow"] .info {
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
} }
:host([veryNarrow]) .name-state { [class*="very-narrow"] .name-state {
padding-right: 0; padding-right: 0;
padding-inline-end: 0; padding-inline-end: 0;
padding-inline-start: initial; padding-inline-start: initial;
@ -663,18 +628,18 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
/* ============= VERY VERY NARROW ============= */ /* ============= VERY VERY NARROW ============= */
:host([veryVeryNarrow]) .info { [class*="very-very-narrow"] .info {
padding-top: 4px; padding-top: 4px;
align-items: center; align-items: center;
} }
:host([veryVeryNarrow]) .content { [class*="very-very-narrow"] .content {
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
} }
:host([veryVeryNarrow]) .icon-image { [class*="very-very-narrow"] .icon-image {
margin-right: 0; margin-right: 0;
margin-inline-end: 0; margin-inline-end: 0;
margin-inline-start: initial; margin-inline-start: initial;