Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/weather-forecast-card.css
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,17 @@ ha-card {
}

.wfc-forecast-container {
pointer-events: auto;
}

.wfc-forecast-container.is-scrollable {
--mask: linear-gradient(
to right,
rgba(0, 0, 0, 0) 0,
rgba(0, 0, 0, 1) var(--fade-width),
rgba(0, 0, 0, 1) calc(100% - var(--fade-width)),
rgba(0, 0, 0, 0) 100%
);
pointer-events: auto;
-webkit-mask: var(--mask);
mask: var(--mask);
}
Expand Down
11 changes: 9 additions & 2 deletions src/weather-forecast-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { createWarningText, normalizeDate } from "./helpers";
import { logger } from "./logger";
import { actionHandler, isInvalidEntityIdError } from "./hass";
import { ForecastActionEvent, ForecastMode } from "./types";
import { classMap } from "lit/directives/class-map.js";
import {
LitElement,
html,
Expand Down Expand Up @@ -66,6 +67,7 @@ export class WeatherForecastCard extends LitElement {
@state() private _hourlyForecastEvent?: ForecastEvent | undefined;
@state() private _currentItemWidth!: number;
@state() private _currentForecastType: ForecastType = "daily";
@state() private _isScrollable = false;

private _hourlyForecastData?: ForecastAttribute[];
private _dailyForecastData?: ForecastAttribute[];
Expand Down Expand Up @@ -138,7 +140,8 @@ export class WeatherForecastCard extends LitElement {
changedProperties.has("_dailyForecastEvent") ||
changedProperties.has("_hourlyForecastEvent") ||
changedProperties.has("_currentForecastType") ||
changedProperties.has("_currentItemWidth")
changedProperties.has("_currentItemWidth") ||
changedProperties.has("_isScrollable")
);
}

Expand Down Expand Up @@ -216,7 +219,10 @@ export class WeatherForecastCard extends LitElement {
${this.config.show_forecast === false
? nothing
: html`<div
class="wfc-forecast-container"
class="${classMap({
"wfc-forecast-container": true,
"is-scrollable": this._isScrollable,
})}"
.actionHandler=${actionHandler({
hasHold: hasAction(
this.config.forecast_action?.hold_action as ActionConfig
Expand Down Expand Up @@ -521,6 +527,7 @@ export class WeatherForecastCard extends LitElement {
const gap = freeSpace > 0 ? freeSpace / (n - 1) : 0;

this._currentItemWidth = calculatedItemWidth + gap;
this._isScrollable = items.length > itemsPerView;

this.style.setProperty("--forecast-item-gap", `${gap}px`);
this.style.setProperty("--forecast-item-width", `${calculatedItemWidth}px`);
Expand Down
35 changes: 35 additions & 0 deletions test/weather-forecast-card.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,41 @@ describe("weather-forecast-card", () => {
expect(newWidth).toBeGreaterThan(initialWidth);
});

it("should add is-scrollable class when content overflows", async () => {
const container = card.shadowRoot!.querySelector(
".wfc-forecast-container"
) as HTMLElement;

// Set container width such that it overflows
Object.defineProperty(container, "clientWidth", {
value: 50, // Small width to ensure overflow (1 item per view, but we have 5)
configurable: true,
});

// Trigger layout
// @ts-expect-error: accessing private method
card.layoutForecastItems(50);
await card.updateComplete;

// @ts-expect-error: accessing private property
expect(card._isScrollable).toBe(true);
expect(container.classList.contains("is-scrollable")).toBe(true);

// Set container width such that it DOES NOT overflow
Object.defineProperty(container, "clientWidth", {
value: 1000, // Large width to ensure it fits (all items fit)
configurable: true,
});

// @ts-expect-error: accessing private method
card.layoutForecastItems(1000);
await card.updateComplete;

// @ts-expect-error: accessing private property
expect(card._isScrollable).toBe(false);
expect(container.classList.contains("is-scrollable")).toBe(false);
});

it("should render 0°C temperature", async () => {
const zeroHourly = [...TEST_FORECAST_HOURLY];
zeroHourly[0] = { ...zeroHourly[0], temperature: 0 };
Expand Down