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 {
CSSResultGroup,
LitElement,
@ -14,7 +15,6 @@ import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_elemen
import { computeStateName } from "../../../common/entity/compute_state_name";
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
import { formatNumber } from "../../../common/number/format_number";
import { debounce } from "../../../common/util/debounce";
import "../../../components/ha-card";
import "../../../components/ha-svg-icon";
import { UNAVAILABLE } from "../../../data/entity";
@ -74,10 +74,21 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
@state() private _subscribed?: Promise<() => void>;
// @todo Consider reworking to eliminate need for attribute since it is manipulated internally
@property({ type: Boolean, reflect: true }) public veryVeryNarrow = false;
private _resizeObserver?: ResizeObserver;
private _sizeController = new ResizeController(this, {
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 _needForecastSubscription() {
return (
@ -118,14 +129,10 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
if (this.hasUpdated && this._config && this.hass) {
this._subscribeForecastEvents();
}
this.updateComplete.then(() => this._attachObserver());
}
public disconnectedCallback(): void {
super.disconnectedCallback();
if (this._resizeObserver) {
this._resizeObserver.disconnect();
}
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 {
super.updated(changedProps);
if (!this._config || !this.hass) {
@ -226,7 +223,10 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
);
const forecast =
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;
const weather = !forecast || this._config?.show_current !== false;
@ -238,6 +238,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
return html`
<ha-card
class=${ifDefined(this._sizeController.value)}
@action=${this._handleAction}
.actionHandler=${actionHandler({
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!);
}
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 {
return typeof item !== "undefined" && item !== null;
}
@ -462,6 +425,11 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
return [
weatherSVGStyles,
css`
:host {
position: relative;
display: block;
height: 100%;
}
ha-card {
cursor: pointer;
outline: none;
@ -612,48 +580,48 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
/* ============= NARROW ============= */
:host([narrow]) .icon-image {
[class*="narrow"] .icon-image {
min-width: 52px;
}
:host([narrow]) .weather-image {
[class*="narrow"] .weather-image {
flex: 0 0 52px;
width: 52px;
}
:host([narrow]) .icon-image .weather-icon {
[class*="narrow"] .icon-image .weather-icon {
--mdc-icon-size: 52px;
}
:host([narrow]) .state,
:host([narrow]) .temp-attribute .temp {
[class*="narrow"] .state,
[class*="narrow"] .temp-attribute .temp {
font-size: 22px;
}
:host([narrow]) .temp-attribute .temp {
[class*="narrow"] .temp-attribute .temp {
margin-right: 16px;
margin-inline-end: 16px;
margin-inline-start: initial;
}
:host([narrow]) .temp span {
[class*="narrow"] .temp span {
top: 1px;
font-size: 16px;
}
/* ============= VERY NARROW ============= */
:host([veryNarrow]) .name,
:host([veryNarrow]) .attribute {
[class*="very-narrow"] .name,
[class*="very-narrow"] .attribute {
display: none;
}
:host([veryNarrow]) .info {
[class*="very-narrow"] .info {
flex-direction: column;
align-items: flex-start;
}
:host([veryNarrow]) .name-state {
[class*="very-narrow"] .name-state {
padding-right: 0;
padding-inline-end: 0;
padding-inline-start: initial;
@ -661,18 +629,18 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
/* ============= VERY VERY NARROW ============= */
:host([veryVeryNarrow]) .info {
[class*="very-very-narrow"] .info {
padding-top: 4px;
align-items: center;
}
:host([veryVeryNarrow]) .content {
[class*="very-very-narrow"] .content {
flex-wrap: wrap;
justify-content: center;
flex-direction: column;
}
:host([veryVeryNarrow]) .icon-image {
[class*="very-very-narrow"] .icon-image {
margin-right: 0;
margin-inline-end: 0;
margin-inline-start: initial;