Use resize controller for weather card (#19806)

* Use resize controller for weather card

* Don't use observe
This commit is contained in:
Paul Bottein 2024-06-26 12:35:49 +02:00 committed by GitHub
parent 7d28f3f585
commit ae94231800
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

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";
@ -74,10 +74,21 @@ 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;
private _resizeObserver?: ResizeObserver; if (width < 245) {
return "very-very-narrow";
}
if (width < 300) {
return "very-narrow";
}
if (width < 375) {
return "narrow";
}
return "regular";
},
});
private _needForecastSubscription() { private _needForecastSubscription() {
return ( return (
@ -118,14 +129,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();
} }
@ -159,16 +166,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) {
@ -226,7 +223,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;
@ -238,6 +238,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),
@ -416,44 +417,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) {
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;
} }
@ -462,6 +425,11 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
return [ return [
weatherSVGStyles, weatherSVGStyles,
css` css`
:host {
position: relative;
display: block;
height: 100%;
}
ha-card { ha-card {
cursor: pointer; cursor: pointer;
outline: none; outline: none;
@ -612,48 +580,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;
@ -661,18 +629,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;