fix(calendar): show unscheduled markers on future days off

This commit is contained in:
syntaxbullet
2026-10-24 20:23:54 +02:00
parent ccd998ab04
commit 7a0cae8f08
7 changed files with 77 additions and 22 deletions

View File

@@ -52,7 +52,7 @@ export function CalendarHeatmap({
const [customRange, setCustomRange] = useState<{ from: string; to: string } | null>(null);
const [rangeError, setRangeError] = useState("");
const latestDate =
allDays.findLast((day) => day.state !== "future")?.date ??
allDays.findLast((day) => !(day.future ?? day.state === "future"))?.date ??
allDays.at(-1)?.date;
// Inspecting a square changes selection, not the window. Only an external
// date outside the visible preset needs a new anchor to bring it into view.

View File

@@ -262,3 +262,20 @@ test("custom timeframe rejects missing, reversed and unavailable dates without c
expect(description(container.querySelector("input")!)).toContain(error!);
}
});
test("upcoming days off render the not-scheduled marker without moving selection past today", async () => {
await act(async () => root.render(<CalendarHeatmap unit="completion" label="Weekly habit" days={[
{ date: "2026-09-04", value: 0, target: 1, state: "due", future: false },
{ date: "2026-09-05", value: 0, target: 1, state: "not-due", future: true },
{ date: "2026-09-06", value: 0, target: 1, state: "future", future: true },
{ date: "2026-09-07", value: 0, target: 1, state: "not-due", future: true },
]} />));
const days = [...container.querySelectorAll<HTMLButtonElement>(".ds-day")];
expect(days.map(day => day.className)).toEqual([
"ds-day ds-day--due", "ds-day ds-day--not-due", "ds-day ds-day--future", "ds-day ds-day--not-due",
]);
expect(days[0]!.getAttribute("aria-pressed")).toBe("true");
expect(days[1]!.getAttribute("aria-label")).toContain("Nothing scheduled");
expect(days[2]!.getAttribute("aria-label")).toContain("Upcoming");
expect(days[1]!.style.backgroundColor).toBe("transparent");
});

View File

@@ -17,6 +17,7 @@ export type CalendarDay = {
date: string;
value: number;
target: number;
future?: boolean;
state: "due" | "not-due" | "future";
};