@@ -196,7 +196,10 @@ export type CalendarProps = CalendarSingleProps | CalendarRangeProps
196196 *
197197 * `mode='single'` (default) commits on day click via `onChange`. `mode='range'`
198198 * stages a start/end selection behind Clear/Cancel/Apply actions (with optional
199- * time-of-day inputs) and commits via `onRangeChange`.
199+ * time-of-day inputs) and commits via `onRangeChange`. The range view is keyed
200+ * on its committed bounds so a newly applied range remounts it with fresh draft
201+ * state (React's "reset all state with a key") — the staged start/end never
202+ * lingers when the source range changes.
200203 *
201204 * @example
202205 * <Calendar value={value} onChange={setValue} />
@@ -205,7 +208,14 @@ export type CalendarProps = CalendarSingleProps | CalendarRangeProps
205208 * <Calendar mode='range' startDate={from} endDate={to} showTime onRangeChange={apply} />
206209 */
207210export function Calendar ( props : CalendarProps ) {
208- if ( props . mode === 'range' ) return < RangeCalendarView { ...props } />
211+ if ( props . mode === 'range' ) {
212+ return (
213+ < RangeCalendarView
214+ key = { `${ String ( props . startDate ?? '' ) } |${ String ( props . endDate ?? '' ) } ` }
215+ { ...props }
216+ />
217+ )
218+ }
209219 return < SingleCalendarView { ...props } />
210220}
211221
@@ -346,32 +356,14 @@ function RangeCalendarView({
346356 className,
347357} : CalendarRangeProps ) {
348358 const seededStart = useMemo ( ( ) => parseDateValue ( startDate ) , [ startDate ] )
349- const { today, view, setView , goToPrevMonth, goToNextMonth, cells } = useCalendarView ( seededStart )
359+ const { today, view, goToPrevMonth, goToNextMonth, cells } = useCalendarView ( seededStart )
350360
351361 const [ rangeStart , setRangeStart ] = useState < Date | null > ( seededStart )
352362 const [ rangeEnd , setRangeEnd ] = useState < Date | null > ( ( ) => parseDateValue ( endDate ) )
353363 const [ selectingEnd , setSelectingEnd ] = useState ( false )
354364 const [ startTime , setStartTime ] = useState ( ( ) => extractTime ( startDate , DEFAULT_RANGE_START_TIME ) )
355365 const [ endTime , setEndTime ] = useState ( ( ) => extractTime ( endDate , DEFAULT_RANGE_END_TIME ) )
356366
357- /**
358- * Resync the staged selection when the bound props change (e.g. a new range
359- * applied elsewhere) so the grid never lingers on a stale draft. Closing the
360- * popover unmounts this view, so a fresh open already re-seeds from props;
361- * this render-phase reset covers prop changes while it stays mounted.
362- */
363- const seedKey = `${ seededStart ?. getTime ( ) ?? '' } |${ parseDateValue ( endDate ) ?. getTime ( ) ?? '' } |${ extractTime ( startDate , DEFAULT_RANGE_START_TIME ) } |${ extractTime ( endDate , DEFAULT_RANGE_END_TIME ) } `
364- const [ prevSeedKey , setPrevSeedKey ] = useState ( seedKey )
365- if ( seedKey !== prevSeedKey ) {
366- setPrevSeedKey ( seedKey )
367- setRangeStart ( seededStart )
368- setRangeEnd ( parseDateValue ( endDate ) )
369- setSelectingEnd ( false )
370- setStartTime ( extractTime ( startDate , DEFAULT_RANGE_START_TIME ) )
371- setEndTime ( extractTime ( endDate , DEFAULT_RANGE_END_TIME ) )
372- if ( seededStart ) setView ( { month : seededStart . getMonth ( ) , year : seededStart . getFullYear ( ) } )
373- }
374-
375367 const pickDay = ( day : number ) => {
376368 const date = new Date ( view . year , view . month , day )
377369 if ( ! selectingEnd || ! rangeStart ) {
0 commit comments