@@ -19,7 +19,11 @@ import {
1919 CalendarWrapper ,
2020} from './Calendar' ;
2121import type { CalendarBodyProps } from './Calendar/types' ;
22- import { addMonths , getFirstOfMonth } from './Calendar/utils/dateGrid' ;
22+ import {
23+ addMonths ,
24+ getFirstOfMonth ,
25+ isDateWithinVisibleMonths ,
26+ } from './Calendar/utils/dateGrid' ;
2327import {
2428 applyRangeOrNewStart ,
2529 handleDateSelectRange ,
@@ -85,8 +89,17 @@ export const DatePickerCalendar: React.FC<DatePickerCalendarProps> = ({
8589 const selectedDate = isRange ? context . startDate : context . selectedDate ;
8690 const endDate = isRange ? context . endDate : undefined ;
8791 const setActiveRangePart = isRange ? context . setActiveRangePart : undefined ;
92+ const activeRangePart = isRange ? context . activeRangePart : null ;
93+
94+ /** Committed value that should drive the visible month when it changes (input, grid, or quick actions). */
95+ const anchorDate = useMemo ( ( ) : Date | null => {
96+ if ( ! isRange ) return selectedDate ?? null ;
97+ if ( activeRangePart === 'end' ) return endDate ?? selectedDate ?? null ;
98+ return selectedDate ?? endDate ?? null ;
99+ } , [ isRange , selectedDate , endDate , activeRangePart ] ) ;
100+
88101 const [ displayDate , setDisplayDate ] = useState ( ( ) =>
89- getFirstOfMonth ( selectedDate ?? new Date ( ) )
102+ getFirstOfMonth ( anchorDate ?? selectedDate ?? endDate ?? new Date ( ) )
90103 ) ;
91104 const [ focusedDate , setFocusedDate ] = useState < Date | null > (
92105 ( ) => selectedDate ?? endDate ?? new Date ( )
@@ -101,22 +114,36 @@ export const DatePickerCalendar: React.FC<DatePickerCalendarProps> = ({
101114 const focusTarget = focusedDate ?? selectedDate ?? endDate ?? new Date ( ) ;
102115 const secondMonthDate = addMonths ( { date : displayDate , n : 1 } ) ;
103116 const isTwoMonthsVisible = useMedia ( `(min-width: ${ breakpoints . xs } )` ) ;
104- const wasOpenRef = useRef ( false ) ;
117+ /** Current left-column month; read in the anchor sync effect without listing `displayDate` in deps (month nav would retrigger and snap back). */
118+ const startOfLeftVisibleMonthRef = useRef ( displayDate ) ;
119+ startOfLeftVisibleMonthRef . current = displayDate ;
105120 /** Wraps both month grids so keyboard focus can move between them without treating it as “outside” the calendar. */
106121 const calendarKeyboardSurfaceRef = useRef < HTMLDivElement > ( null ) ;
107122
108- // Sync visible month to selection only when the calendar opens, not on every
109- // date click. Otherwise clicking a date in the second month would jump the view.
123+ // When the committed anchor changes while the popover is open (typed input, grid, quick action),
124+ // move focus to that day. Shift the visible month pair only if the anchor is not already shown
125+ // (including the second column in a two-month layout), so picking in the right-hand month does
126+ // not jump the view.
110127 useEffect ( ( ) => {
111- const justOpened = isCalendarOpen && ! wasOpenRef . current ;
112- wasOpenRef . current = isCalendarOpen ;
113- if ( ! justOpened ) return ;
114- const anchor = selectedDate ?? endDate ;
115- if ( anchor ) {
128+ if ( ! isCalendarOpen ) {
129+ return ;
130+ }
131+ const anchor = anchorDate ;
132+ if ( ! anchor ) {
133+ return ;
134+ }
135+
136+ const alreadyVisible = isDateWithinVisibleMonths ( {
137+ date : anchor ,
138+ startOfLeftVisibleMonth : startOfLeftVisibleMonthRef . current ,
139+ showSecondMonth : isTwoMonthsVisible ,
140+ } ) ;
141+
142+ if ( ! alreadyVisible ) {
116143 setDisplayDate ( getFirstOfMonth ( anchor ) ) ;
117- setFocusedDate ( selectedDate ?? endDate ?? new Date ( ) ) ;
118144 }
119- } , [ isCalendarOpen , selectedDate , endDate ] ) ;
145+ setFocusedDate ( anchor ) ;
146+ } , [ isCalendarOpen , anchorDate , isTwoMonthsVisible ] ) ;
120147
121148 const onDateSelect = useCallback (
122149 ( date : Date ) => {
@@ -235,7 +262,9 @@ export const DatePickerCalendar: React.FC<DatePickerCalendarProps> = ({
235262 headingId = { headingId }
236263 hideLastNav
237264 locale = { locale }
238- onDisplayDateChange = { setDisplayDate }
265+ onDisplayDateChange = { ( ) =>
266+ setDisplayDate ( ( prev ) => addMonths ( { date : prev , n : 1 } ) )
267+ }
239268 />
240269 < CalendarBody
241270 calendarKeyboardSurfaceRef = { calendarKeyboardSurfaceRef }
@@ -250,7 +279,9 @@ export const DatePickerCalendar: React.FC<DatePickerCalendarProps> = ({
250279 shouldDisableDate = { shouldDisableDate }
251280 weekStartsOn = { weekStartsOn }
252281 onDateSelect = { onDateSelect }
253- onDisplayDateChange = { setDisplayDate }
282+ onDisplayDateChange = { ( ) =>
283+ setDisplayDate ( ( prev ) => addMonths ( { date : prev , n : 1 } ) )
284+ }
254285 onEscapeKeyPress = { closeCalendar }
255286 onFocusedDateChange = { onFocusedDateChange }
256287 />
0 commit comments