diff --git a/src/components/design-system/CalendarHeatmap.tsx b/src/components/design-system/CalendarHeatmap.tsx
index 173176c..831ffee 100644
--- a/src/components/design-system/CalendarHeatmap.tsx
+++ b/src/components/design-system/CalendarHeatmap.tsx
@@ -44,11 +44,18 @@ export function CalendarHeatmap({
const latestDate =
allDays.findLast((day) => day.state !== "future")?.date ??
allDays.at(-1)?.date;
- // A date selected in the editor must stay visible even outside the current window.
- const anchor =
- controlledDate && allDays.some((day) => day.date === controlledDate)
- ? controlledDate
- : latestDate;
+ // 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.
+ const [windowAnchor, setWindowAnchor] = useState({ latestDate, date: latestDate });
+ let anchor = windowAnchor.latestDate === latestDate ? windowAnchor.date : latestDate;
+ if (months !== "custom" && anchor && controlledDate &&
+ allDays.some(day => day.date === controlledDate) &&
+ !visibleCalendarDays(allDays, months, anchor).some(day => day.date === controlledDate)) {
+ anchor = controlledDate;
+ }
+ if (windowAnchor.latestDate !== latestDate || windowAnchor.date !== anchor) {
+ setWindowAnchor({ latestDate, date: anchor });
+ }
const [localSelectedDate, setLocalSelectedDate] = useState(anchor);
const selectedDate = controlledDate ?? localSelectedDate;
function setSelectedDate(date: string) {
diff --git a/src/components/design-system/accessibility.test.tsx b/src/components/design-system/accessibility.test.tsx
index 92042f3..c8e5008 100644
--- a/src/components/design-system/accessibility.test.tsx
+++ b/src/components/design-system/accessibility.test.tsx
@@ -66,7 +66,7 @@ test("calendar associates exact keyboard guidance and preserves focus when selec
expect(selected.tabIndex).toBe(0);
});
-test("calendar focuses the accepted date after a controlled month window changes", async () => {
+test("calendar focuses the accepted date when selection crosses a month boundary", async () => {
function Calendar() {
const [date, setDate] = useState("2026-09-01");
return ;
@@ -105,6 +105,55 @@ test("rejected calendar clicks and repeated arrows do not leave stale focus requ
expect(rejected.getAttribute("aria-pressed")).toBe("true");
});
+test("selecting tracked, empty, unscheduled and future dates never changes the displayed timeline", async () => {
+ const days = demoCalendar(3, 8).map((day, index) => ({ ...day,
+ state: day.state === "future" ? day.state : index % 2 === 0 ? "not-due" as const : "due" as const,
+ value: index % 3 === 0 ? 0 : day.value,
+ }));
+ function Calendar() {
+ const [date, setDate] = useState();
+ return ;
+ }
+ await act(async () => root.render());
+ const timeline = () => ({
+ dates: [...container.querySelectorAll(".ds-day")].map(day => day.getAttribute("aria-label")?.slice(0, 10)),
+ months: [...container.querySelectorAll(".ds-calendar-month-label")].map(month => month.textContent),
+ range: container.querySelector(".ds-calendar-range-label")?.textContent,
+ weeks: (container.querySelector(".ds-calendar") as HTMLElement).style.getPropertyValue("--calendar-weeks"),
+ });
+ for (const preset of [12, 6, 4, 3, "Custom"]) {
+ await act(async () => button(typeof preset === "number" ? `${preset}m` : preset).click());
+ const before = timeline();
+ for (const index of [1, 0, 8, 7, before.dates.length - 1]) {
+ const date = before.dates[index]!;
+ await act(async () => container.querySelector(`.ds-day[aria-label^="${date}:"]`)!.click());
+ expect(timeline()).toEqual(before);
+ expect(container.querySelector('.ds-day[aria-pressed="true"]')?.getAttribute("aria-label")).toStartWith(`${date}:`);
+ }
+ for (const key of ["ArrowLeft", "Home", "End"]) {
+ const selected = container.querySelector('.ds-day[aria-pressed="true"]')!;
+ await act(async () => selected.dispatchEvent(new dom.KeyboardEvent("keydown", { key, bubbles: true }) as unknown as KeyboardEvent));
+ expect(timeline()).toEqual(before);
+ }
+ }
+});
+
+test("an external editor date outside the window remains reachable without moving focus", async () => {
+ let setDate!: (date: string) => void;
+ function Calendar() {
+ const [date, update] = useState("2026-09-04");
+ setDate = update;
+ return <>>;
+ }
+ await act(async () => root.render());
+ await act(async () => button("3m").click());
+ const editor = container.querySelector('input[aria-label="Editor date"]')!;
+ editor.focus();
+ await act(async () => setDate("2026-03-04"));
+ expect(container.querySelector('.ds-day[aria-pressed="true"]')?.getAttribute("aria-label")).toStartWith("2026-03-04:");
+ expect(document.activeElement).toBe(editor);
+});
+
test("editor controls expose their explanatory hints", async () => {
await act(async () => root.render());
expect(description(container.querySelector("input[readonly]")!)).toContain("Method is fixed");