From eb298e786e3e4dd364cec705b2c9c32249127b31 Mon Sep 17 00:00:00 2001 From: Ruslan Bakiev <572431+veikab@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:11:55 +0700 Subject: [PATCH] calendar: prevent zoom-in instant switch when anchor is offscreen --- frontend/app.vue | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/frontend/app.vue b/frontend/app.vue index 7f32b32..b06092a 100644 --- a/frontend/app.vue +++ b/frontend/app.vue @@ -2577,13 +2577,20 @@ function resolveMonthAnchor(event?: WheelEvent) { return calendarCursor.value.getMonth(); } +function fallbackMonthGridAnchorKey() { + if (monthCells.value.some((cell) => cell.key === selectedDateKey.value)) return selectedDateKey.value; + const middle = dayKey(new Date(calendarCursor.value.getFullYear(), calendarCursor.value.getMonth(), 15)); + if (monthCells.value.some((cell) => cell.key === middle)) return middle; + return monthCells.value.find((cell) => cell.inMonth)?.key ?? monthCells.value[0]?.key ?? selectedDateKey.value; +} + function resolveWeekAnchor(event?: WheelEvent) { const target = event?.target as HTMLElement | null; const weekKey = target?.closest("[data-calendar-week-start-key]")?.dataset.calendarWeekStartKey; if (weekKey) return weekKey; if (calendarHoveredWeekStartKey.value) return calendarHoveredWeekStartKey.value; if (calendarHoveredDayKey.value) return calendarHoveredDayKey.value; - return selectedDateKey.value; + return fallbackMonthGridAnchorKey(); } function resolveDayAnchor(event?: WheelEvent) { @@ -2591,14 +2598,16 @@ function resolveDayAnchor(event?: WheelEvent) { const dayKeyAttr = target?.closest("[data-calendar-day-key]")?.dataset.calendarDayKey; if (dayKeyAttr) return dayKeyAttr; if (calendarHoveredDayKey.value) return calendarHoveredDayKey.value; - return selectedDateKey.value; + return weekDays.value[0]?.key ?? selectedDateKey.value; } async function zoomInCalendar(event?: Event) { const wheelEvent = event instanceof WheelEvent ? event : undefined; if (calendarView.value === "year") { const monthIndex = resolveMonthAnchor(wheelEvent); - const sourceElement = queryCalendarElement(`[data-calendar-month-index="${monthIndex}"]`); + const sourceElement = + queryCalendarElement(`[data-calendar-month-index="${monthIndex}"]`) ?? + queryCalendarElement("[data-calendar-month-index]"); if (maybePrimeWheelZoom(wheelEvent, calendarPrimeMonthToken(monthIndex))) return; await animateCalendarZoomIn(sourceElement, zoomGhostForMonth(monthIndex), () => { openYearMonth(monthIndex); @@ -2611,7 +2620,9 @@ async function zoomInCalendar(event?: Event) { const rowStartKey = weekRowStartForDate(anchorDayKey); const sourceElement = queryCalendarElement(`[data-calendar-week-start-key="${rowStartKey}"]`) ?? - queryCalendarElement(`[data-calendar-day-key="${anchorDayKey}"]`); + queryCalendarElement(`[data-calendar-day-key="${anchorDayKey}"]`) ?? + queryCalendarElement("[data-calendar-week-start-key]") ?? + queryCalendarElement("[data-calendar-day-key]"); if (maybePrimeWheelZoom(wheelEvent, calendarPrimeWeekToken(rowStartKey))) return; await animateCalendarZoomIn( sourceElement, @@ -2625,7 +2636,7 @@ async function zoomInCalendar(event?: Event) { if (calendarView.value === "week") { const dayAnchor = resolveDayAnchor(wheelEvent); - const sourceElement = queryCalendarElement(`[data-calendar-day-key="${dayAnchor}"]`); + const sourceElement = queryCalendarElement(`[data-calendar-day-key="${dayAnchor}"]`) ?? queryCalendarElement("[data-calendar-day-key]"); if (maybePrimeWheelZoom(wheelEvent, calendarPrimeDayToken(dayAnchor))) return; await animateCalendarZoomIn(sourceElement, zoomGhostForDay(dayAnchor), () => { openDayView(dayAnchor);