import classNames from "classnames" ; import * as React from "react" ; import DayPicker , { CaptionElementProps , DayModifiers , DayPickerProps , NavbarElementProps } from "react-day-picker" ; import { polyfill } from "react-lifecycles-compat" ; import { AbstractPureComponent2 , Boundary , DISPLAYNAME_PREFIX , Divider , Props } from "@blueprintjs/core" ; import * as DateClasses from "./common/classes" ; import { DateRange } from "./common/dateRange" ; import * as DateUtils from "./common/dateUtils" ; import * as Errors from "./common/errors" ; import { MonthAndYear } from "./common/monthAndYear" ; import { DatePickerCaption } from "./datePickerCaption" ; import { combineModifiers , getDefaultMaxDate , getDefaultMinDate , HOVERED_RANGE_MODIFIER , IDatePickerBaseProps , DatePickerModifiers , SELECTED_RANGE_MODIFIER , } from "./datePickerCore" ; import { DatePickerNavbar } from "./datePickerNavbar" ; import { DateRangeSelectionStrategy } from "./dateRangeSelectionStrategy" ; import { DateRangeShortcut , Shortcuts } from "./shortcuts" ; import { TimePicker } from "./timePicker" ; export type DateRangePickerProps = IDateRangePickerProps ; deprecated export interface IDateRangePickerProps extends IDatePickerBaseProps , Props { default allowSingleDayRange ? : boolean ; /**
     * The date-range boundary that the next click should modify.
     * This will be honored unless the next click would overlap the other boundary date.
     * In that case, the two boundary dates will be auto-swapped to keep them in chronological order.
     * If `undefined`, the picker will revert to its default selection behavior.
     */ boundaryToModify ? : Boundary ; default contiguousCalendarMonths ? : boolean ; /**
     * Initial `DateRange` the calendar will display as selected.
     * This should not be set if `value` is set.
     */ defaultValue ? : DateRange ; /**
     * Called when the user selects a day.
     * If no days are selected, it will pass `[null, null]`.
     * If a start date is selected but not an end date, it will pass `[selectedDate, null]`.
     * If both a start and end date are selected, it will pass `[startDate, endDate]`.
     */ onChange ? : ( selectedDates : DateRange ) => void ; /**
     * Called when the user changes the hovered date range, either from mouseenter or mouseleave.
     * When triggered from mouseenter, it will pass the date range that would result from next click.
     * When triggered from mouseleave, it will pass `undefined`.
     */ onHoverChange ? : ( hoveredDates : DateRange , hoveredDay : Date , hoveredBoundary : Boundary ) => void ; /**
     * Called when the `shortcuts` props is enabled and the user changes the shortcut.
     */ onShortcutChange ? : ( shortcut : DateRangeShortcut , index : number ) => void ; default shortcuts ? : boolean | DateRangeShortcut [ ] ; /**
     * The currently selected shortcut.
     * If this prop is provided, the component acts in a controlled manner.
     */ selectedShortcutIndex ? : number ; default singleMonthOnly ? : boolean ; /**
     * The currently selected `DateRange`.
     * If this prop is provided, the component acts in a controlled manner.
     */ value ? : DateRange ; } export interface IDateRangePickerState { hoverValue ? : DateRange ; leftView ? : MonthAndYear ; rightView ? : MonthAndYear ; value ? : DateRange ; time ? : DateRange ; selectedShortcutIndex ? : number ; } @ polyfill export class DateRangePicker extends AbstractPureComponent2 < DateRangePickerProps , IDateRangePickerState > { public static defaultProps : DateRangePickerProps = { allowSingleDayRange : false , contiguousCalendarMonths : true , dayPickerProps : { } , maxDate : getDefaultMaxDate ( ) , minDate : getDefaultMinDate ( ) , reverseMonthAndYearMenus : false , shortcuts : true , singleMonthOnly : false , timePickerProps : { } , } ; public static displayName = `${ DISPLAYNAME_PREFIX }.DateRangePicker` ; private modifiers : DatePickerModifiers = { [ SELECTED_RANGE_MODIFIER ] : day => { const { value } = this . state ; return value [ 0 ] != null && value [ 1 ] != null && DateUtils . isDayInRange ( day , value , true ) ; } , [ `${ SELECTED_RANGE_MODIFIER }-start` ] : day => DateUtils . areSameDay ( this . state . value [ 0 ] , day ) , [ `${ SELECTED_RANGE_MODIFIER }-end` ] : day => DateUtils . areSameDay ( this . state . value [ 1 ] , day ) , [ HOVERED_RANGE_MODIFIER ] : day => { const { hoverValue , value : [ selectedStart , selectedEnd ] , } = this . state ; if ( selectedStart == null && selectedEnd == null ) { return false ; } if ( hoverValue == null || hoverValue [ 0 ] == null || hoverValue [ 1 ] == null ) { return false ; } return DateUtils . isDayInRange ( day , hoverValue , true ) ; } , [ `${ HOVERED_RANGE_MODIFIER }-start` ] : day => { const { hoverValue } = this . state ; if ( hoverValue == null || hoverValue [ 0 ] == null ) { return false ; } return DateUtils . areSameDay ( hoverValue [ 0 ] , day ) ; } , [ `${ HOVERED_RANGE_MODIFIER }-end` ] : day => { const { hoverValue } = this . state ; if ( hoverValue == null || hoverValue [ 1 ] == null ) { return false ; } return DateUtils . areSameDay ( hoverValue [ 1 ] , day ) ; } , } ; public constructor ( props , context ? ) { super ( props , context ) ; const value = getInitialValue ( props ) ; const time = value ; const initialMonth = getInitialMonth ( props , value ) ; const initialMonthEqualsMinMonth = DateUtils . areSameMonth ( initialMonth , props . minDate ) ; const initalMonthEqualsMaxMonth = DateUtils . areSameMonth ( initialMonth , props . maxDate ) ; if ( ! props . singleMonthOnly && ! initialMonthEqualsMinMonth && initalMonthEqualsMaxMonth ) { initialMonth . setMonth ( initialMonth . getMonth ( ) - 1 ) ; } const leftView = MonthAndYear . fromDate ( initialMonth ) ; const rightDate = value [ 1 ] ; const rightView = ! props . contiguousCalendarMonths && rightDate != null && ! DateUtils . areSameMonth ( initialMonth , rightDate ) ? MonthAndYear . fromDate ( rightDate ) : leftView . getNextMonth ( ) ; this . state = { hoverValue : [ null , null ] , leftView , rightView , selectedShortcutIndex : this . props . selectedShortcutIndex !== undefined ? this . props . selectedShortcutIndex : - 1 , time , value , } ; } public render ( ) { const { className , contiguousCalendarMonths , singleMonthOnly } = this . props ; const isShowingOneMonth = singleMonthOnly || DateUtils . areSameMonth ( this . props . minDate , this . props . maxDate ) ; const classes = classNames ( DateClasses . DATEPICKER , DateClasses . DATERANGEPICKER , className , { [ DateClasses . DATERANGEPICKER_CONTIGUOUS ] : contiguousCalendarMonths , [ DateClasses . DATERANGEPICKER_SINGLE_MONTH ] : isShowingOneMonth , } ) ; return ( < div className = { classes } > { this . maybeRenderShortcuts ( ) } < div > { this . renderCalendars ( isShowingOneMonth ) } { this . maybeRenderTimePickers ( ) } < /div> < /div>); } public componentDidUpdate ( prevProps , prevState ) { super . componentDidUpdate ( prevProps , prevState ) ; if ( ! DateUtils . areRangesEqual ( prevProps . value , this . props . value ) || prevProps . contiguousCalendarMonths !== this . props . contiguousCalendarMonths ) { const nextState = getStateChange ( prevProps . value , this . props . value , this . state , prevProps . contiguousCalendarMonths ) ; this . setState ( nextState ) ; } if ( this . props . selectedShortcutIndex !== prevProps . selectedShortcutIndex ) { this . setState ( { selectedShortcutIndex : this . props . selectedShortcutIndex } ) ; } } protected validateProps ( props ) { const { defaultValue , initialMonth , maxDate , minDate , boundaryToModify , value } = props ; const dateRange = [ minDate , maxDate ] ; if ( defaultValue != null && ! DateUtils . isDayRangeInRange ( defaultValue , dateRange ) ) { console . error ( Errors . DATERANGEPICKER_DEFAULT_VALUE_INVALID ) ; } if ( initialMonth != null && ! DateUtils . isMonthInRange ( initialMonth , dateRange ) ) { console . error ( Errors . DATERANGEPICKER_INITIAL_MONTH_INVALID ) ; } if ( maxDate != null && minDate != null && maxDate < minDate && ! DateUtils . areSameDay ( maxDate , minDate ) ) { console . error ( Errors . DATERANGEPICKER_MAX_DATE_INVALID ) ; } if ( value != null && ! DateUtils . isDayRangeInRange ( value , dateRange ) ) { console . error ( Errors . DATERANGEPICKER_VALUE_INVALID ) ; } if ( boundaryToModify != null && boundaryToModify !== Boundary . START && boundaryToModify !== Boundary . END ) { console . error ( Errors . DATERANGEPICKER_PREFERRED_BOUNDARY_TO_MODIFY_INVALID ) ; } } private shouldHighlightCurrentDay = ( date ) => { const { highlightCurrentDay } = this . props ; return highlightCurrentDay && DateUtils . isToday ( date ) ; } ; private getDateRangePickerModifiers = ( ) => { const { modifiers } = this . props ; return combineModifiers ( this . modifiers , { isToday : this . shouldHighlightCurrentDay , ... modifiers , } ) ; } ; private renderDay = ( day ) => { const date = day . getDate ( ) ; return < div className = { DateClasses . DATEPICKER_DAY_WRAPPER } > { date } < /div>; } ; private disabledDays = ( day ) => ! DateUtils . isDayInRange ( day , [ this . props . minDate , this . props . maxDate ] ) ; private getDisabledDaysModifier = ( ) => { const { dayPickerProps : { disabledDays } , } = this . props ; return disabledDays instanceof Array ? [ this . disabledDays , ... disabledDays ] : [ this . disabledDays , disabledDays ] ; } ; private maybeRenderShortcuts ( ) { const { shortcuts } = this . props ; if ( shortcuts == null || shortcuts === false ) { return null ; } const { selectedShortcutIndex } = this . state ; const { allowSingleDayRange , maxDate , minDate , timePrecision } = this . props ; return [ < Shortcuts key = "shortcuts" { ... { allowSingleDayRange , maxDate , minDate , selectedShortcutIndex , shortcuts , timePrecision , } } onShortcutClick = { this . handleShortcutClick } / > , < Divider key = "div" / > , ] ; } private maybeRenderTimePickers ( ) { const { timePrecision , timePickerProps } = this . props ; if ( timePrecision == null && timePickerProps === DateRangePicker . defaultProps . timePickerProps ) { return null ; } return ( < div className = { DateClasses . DATERANGEPICKER_TIMEPICKERS } > < TimePicker precision = { timePrecision } { ... timePickerProps } onChange = { this . handleTimeChangeLeftCalendar } value = { this . state . time [ 0 ] } / > < TimePicker precision = { timePrecision } { ... timePickerProps } onChange = { this . handleTimeChangeRightCalendar } value = { this . state . time [ 1 ] } / > < /div>); } private handleTimeChange = ( newTime , dateIndex ) => { this . props . timePickerProps ?. onChange ?. ( newTime ) ; const { value , time } = this . state ; const newValue = DateUtils . getDateTime ( value [ dateIndex ] != null ? DateUtils . clone ( value [ dateIndex ] ) : new Date ( ) , newTime ) ; const newDateRange = [ value [ 0 ] , value [ 1 ] ] ; newDateRange [ dateIndex ] = newValue ; const newTimeRange = [ time [ 0 ] , time [ 1 ] ] ; newTimeRange [ dateIndex ] = newTime ; this . props . onChange ?. ( newDateRange ) ; this . setState ( { value : newDateRange , time : newTimeRange } ) ; } ; private handleTimeChangeLeftCalendar = ( time ) => { this . handleTimeChange ( time , 0 ) ; } ; private handleTimeChangeRightCalendar = ( time ) => { this . handleTimeChange ( time , 1 ) ; } ; private renderCalendars ( isShowingOneMonth ) { const { dayPickerProps , locale , localeUtils , maxDate , minDate } = this . props ; const dayPickerBaseProps = { locale , localeUtils , modifiers : this . getDateRangePickerModifiers ( ) , showOutsideDays : true , ... dayPickerProps , disabledDays : this . getDisabledDaysModifier ( ) , onDayClick : this . handleDayClick , onDayMouseEnter : this . handleDayMouseEnter , onDayMouseLeave : this . handleDayMouseLeave , selectedDays : this . state . value , } ; if ( isShowingOneMonth ) { return ( < DayPicker { ... dayPickerBaseProps } captionElement = { this . renderSingleCaption } navbarElement = { this . renderSingleNavbar } fromMonth = { minDate } month = { this . state . leftView . getFullDate ( ) } numberOfMonths = { 1 } onMonthChange = { this . handleLeftMonthChange } toMonth = { maxDate } renderDay = { dayPickerProps ?. renderDay ?? this . renderDay } />); } else { return [ < DayPicker key = "left" { ... dayPickerBaseProps } canChangeMonth = { true } captionElement = { this . renderLeftCaption } navbarElement = { this . renderLeftNavbar } fromMonth = { minDate } month = { this . state . leftView . getFullDate ( ) } numberOfMonths = { 1 } onMonthChange = { this . handleLeftMonthChange } toMonth = { DateUtils . getDatePreviousMonth ( maxDate ) } renderDay = { dayPickerProps ?. renderDay ?? this . renderDay } />, < DayPicker key = "right" { ... dayPickerBaseProps } canChangeMonth = { true } captionElement = { this . renderRightCaption } navbarElement = { this . renderRightNavbar } fromMonth = { DateUtils . getDateNextMonth ( minDate ) } month = { this . state . rightView . getFullDate ( ) } numberOfMonths = { 1 } onMonthChange = { this . handleRightMonthChange } toMonth = { maxDate } renderDay = { dayPickerProps ?. renderDay ?? this . renderDay } />, ] ; } } private renderSingleNavbar = ( navbarProps ) => ( < DatePickerNavbar { ... navbarProps } maxDate = { this . props . maxDate } minDate = { this . props . minDate } / > ) ; private renderLeftNavbar = ( navbarProps ) => ( < DatePickerNavbar { ... navbarProps } hideRightNavButton = { this . props . contiguousCalendarMonths } maxDate = { this . props . maxDate } minDate = { this . props . minDate } / > ) ; private renderRightNavbar = ( navbarProps ) => ( < DatePickerNavbar { ... navbarProps } hideLeftNavButton = { this . props . contiguousCalendarMonths } maxDate = { this . props . maxDate } minDate = { this . props . minDate } / > ) ; private renderSingleCaption = ( captionProps ) => ( < DatePickerCaption { ... captionProps } maxDate = { this . props . maxDate } minDate = { this . props . minDate } onMonthChange = { this . handleLeftMonthSelectChange } onYearChange = { this . handleLeftYearSelectChange } reverseMonthAndYearMenus = { this . props . reverseMonthAndYearMenus } / > ) ; private renderLeftCaption = ( captionProps ) => ( < DatePickerCaption { ... captionProps } maxDate = { DateUtils . getDatePreviousMonth ( this . props . maxDate ) } minDate = { this . props . minDate } onMonthChange = { this . handleLeftMonthSelectChange } onYearChange = { this . handleLeftYearSelectChange } reverseMonthAndYearMenus = { this . props . reverseMonthAndYearMenus } / > ) ; private renderRightCaption = ( captionProps ) => ( < DatePickerCaption { ... captionProps } maxDate = { this . props . maxDate } minDate = { DateUtils . getDateNextMonth ( this . props . minDate ) } onMonthChange = { this . handleRightMonthSelectChange } onYearChange = { this . handleRightYearSelectChange } reverseMonthAndYearMenus = { this . props . reverseMonthAndYearMenus } / > ) ; private handleDayMouseEnter = ( day , modifiers , e ) => { this . props . dayPickerProps . onDayMouseEnter ?. ( day , modifiers , e ) ; if ( modifiers . disabled ) { return ; } const { dateRange , boundary } = DateRangeSelectionStrategy . getNextState ( this . state . value , day , this . props . allowSingleDayRange , this . props . boundaryToModify ) ; this . setState ( { hoverValue : dateRange } ) ; this . props . onHoverChange ?. ( dateRange , day , boundary ) ; } ; private handleDayMouseLeave = ( day , modifiers , e ) => { this . props . dayPickerProps . onDayMouseLeave ?. ( day , modifiers , e ) ; if ( modifiers . disabled ) { return ; } this . setState ( { hoverValue : undefined } ) ; this . props . onHoverChange ?. ( undefined , day , undefined ) ; } ; private handleDayClick = ( day , modifiers , e ) => { this . props . dayPickerProps . onDayClick ?. ( day , modifiers , e ) ; if ( modifiers . disabled ) { this . forceUpdate ( ) ; return ; } const nextValue = DateRangeSelectionStrategy . getNextState ( this . state . value , day , this . props . allowSingleDayRange , this . props . boundaryToModify ) . dateRange ; this . handleDayMouseEnter ( day , modifiers , e ) ; this . handleNextState ( nextValue ) ; } ; private handleShortcutClick = ( shortcut , selectedShortcutIndex ) => { const { onChange , contiguousCalendarMonths , onShortcutChange } = this . props ; const { dateRange , includeTime } = shortcut ; if ( includeTime ) { const newDateRange = [ dateRange [ 0 ] , dateRange [ 1 ] ] ; const newTimeRange = [ dateRange [ 0 ] , dateRange [ 1 ] ] ; const nextState = getStateChange ( this . state . value , dateRange , this . state , contiguousCalendarMonths ) ; this . setState ( { ... nextState , time : newTimeRange } ) ; onChange ?. ( newDateRange ) ; } else { this . handleNextState ( dateRange ) ; } if ( this . props . selectedShortcutIndex === undefined ) { this . setState ( { selectedShortcutIndex } ) ; } onShortcutChange ?. ( shortcut , selectedShortcutIndex ) ; } ; private handleNextState = ( nextValue ) => { const { value } = this . state ; nextValue [ 0 ] = DateUtils . getDateTime ( nextValue [ 0 ] , this . state . time [ 0 ] ) ; nextValue [ 1 ] = DateUtils . getDateTime ( nextValue [ 1 ] , this . state . time [ 1 ] ) ; const nextState = getStateChange ( value , nextValue , this . state , this . props . contiguousCalendarMonths ) ; if ( this . props . value == null ) { this . setState ( nextState ) ; } this . props . onChange ?. ( nextValue ) ; } ; private handleLeftMonthChange = ( newDate ) => { const leftView = MonthAndYear . fromDate ( newDate ) ; this . props . dayPickerProps . onMonthChange ?. ( leftView . getFullDate ( ) ) ; this . updateLeftView ( leftView ) ; } ; private handleRightMonthChange = ( newDate ) => { const rightView = MonthAndYear . fromDate ( newDate ) ; this . props . dayPickerProps . onMonthChange ?. ( rightView . getFullDate ( ) ) ; this . updateRightView ( rightView ) ; } ; private handleLeftMonthSelectChange = ( leftMonth ) => { const leftView = new MonthAndYear ( leftMonth , this . state . leftView . getYear ( ) ) ; this . props . dayPickerProps . onMonthChange ?. ( leftView . getFullDate ( ) ) ; this . updateLeftView ( leftView ) ; } ; private handleRightMonthSelectChange = ( rightMonth ) => { const rightView = new MonthAndYear ( rightMonth , this . state . rightView . getYear ( ) ) ; this . props . dayPickerProps . onMonthChange ?. ( rightView . getFullDate ( ) ) ; this . updateRightView ( rightView ) ; } ; private updateLeftView ( leftView ) { let rightView = this . state . rightView . clone ( ) ; if ( ! leftView . isBefore ( rightView ) || this . props . contiguousCalendarMonths ) { rightView = leftView . getNextMonth ( ) ; } this . setViews ( leftView , rightView ) ; } private updateRightView ( rightView ) { let leftView = this . state . leftView . clone ( ) ; if ( ! rightView . isAfter ( leftView ) || this . props . contiguousCalendarMonths ) { leftView = rightView . getPreviousMonth ( ) ; } this . setViews ( leftView , rightView ) ; } private handleLeftYearSelectChange = ( leftDisplayYear ) => { let leftView = new MonthAndYear ( this . state . leftView . getMonth ( ) , leftDisplayYear ) ; this . props . dayPickerProps . onMonthChange ?. ( leftView . getFullDate ( ) ) ; const { minDate , maxDate } = this . props ; const adjustedMaxDate = DateUtils . getDatePreviousMonth ( maxDate ) ; const minMonthAndYear = new MonthAndYear ( minDate . getMonth ( ) , minDate . getFullYear ( ) ) ; const maxMonthAndYear = new MonthAndYear ( adjustedMaxDate . getMonth ( ) , adjustedMaxDate . getFullYear ( ) ) ; if ( leftView . isBefore ( minMonthAndYear ) ) { leftView = minMonthAndYear ; } else if ( leftView . isAfter ( maxMonthAndYear ) ) { leftView = maxMonthAndYear ; } let rightView = this . state . rightView . clone ( ) ; if ( ! leftView . isBefore ( rightView ) || this . props . contiguousCalendarMonths ) { rightView = leftView . getNextMonth ( ) ; } this . setViews ( leftView , rightView ) ; } ; private handleRightYearSelectChange = ( rightDisplayYear ) => { let rightView = new MonthAndYear ( this . state . rightView . getMonth ( ) , rightDisplayYear ) ; this . props . dayPickerProps . onMonthChange ?. ( rightView . getFullDate ( ) ) ; const { minDate , maxDate } = this . props ; const adjustedMinDate = DateUtils . getDateNextMonth ( minDate ) ; const minMonthAndYear = MonthAndYear . fromDate ( adjustedMinDate ) ; const maxMonthAndYear = MonthAndYear . fromDate ( maxDate ) ; if ( rightView . isBefore ( minMonthAndYear ) ) { rightView = minMonthAndYear ; } else if ( rightView . isAfter ( maxMonthAndYear ) ) { rightView = maxMonthAndYear ; } let leftView = this . state . leftView . clone ( ) ; if ( ! rightView . isAfter ( leftView ) || this . props . contiguousCalendarMonths ) { leftView = rightView . getPreviousMonth ( ) ; } this . setViews ( leftView , rightView ) ; } ; private setViews ( leftView , rightView ) { this . setState ( { leftView , rightView } ) ; } } function getStateChange ( value , nextValue , state , contiguousCalendarMonths ) { if ( value != null && nextValue == null ) { return { value : [ null , null ] } ; } else if ( nextValue != null ) { let leftView = state . leftView . clone ( ) ; let rightView = state . rightView . clone ( ) ; const nextValueStartView = MonthAndYear . fromDate ( nextValue [ 0 ] ) ; const nextValueEndView = MonthAndYear . fromDate ( nextValue [ 1 ] ) ; if ( nextValueStartView == null && nextValueEndView != null ) { if ( ! nextValueEndView . isSame ( leftView ) && ! nextValueEndView . isSame ( rightView ) ) { rightView = nextValueEndView ; if ( ! leftView . isBefore ( rightView ) ) { leftView = rightView . getPreviousMonth ( ) ; } } } else if ( nextValueStartView != null && nextValueEndView == null ) { if ( ! nextValueStartView . isSame ( leftView ) && ! nextValueStartView . isSame ( rightView ) ) { leftView = nextValueStartView ; if ( ! rightView . isAfter ( leftView ) ) { rightView = leftView . getNextMonth ( ) ; } } } else if ( nextValueStartView != null && nextValueEndView != null ) { if ( nextValueStartView . isSame ( nextValueEndView ) ) { if ( leftView . isSame ( nextValueStartView ) || rightView . isSame ( nextValueStartView ) ) { } else { leftView = nextValueStartView ; rightView = nextValueStartView . getNextMonth ( ) ; } } else { if ( ! leftView . isSame ( nextValueStartView ) ) { leftView = nextValueStartView ; rightView = nextValueStartView . getNextMonth ( ) ; } if ( contiguousCalendarMonths === false && ! rightView . isSame ( nextValueEndView ) ) { rightView = nextValueEndView ; } } } return { leftView , rightView , value : nextValue , } ; } else if ( contiguousCalendarMonths === true ) { if ( ! state . leftView . getNextMonth ( ) . isSameMonth ( state . rightView ) ) { const nextRightView = state . leftView . getNextMonth ( ) ; return { rightView : nextRightView } ; } } return { } ; } function getInitialValue ( props ) { if ( props . value != null ) { return props . value ; } if ( props . defaultValue != null ) { return props . defaultValue ; } return [ null , null ] ; } function getInitialMonth ( props , value ) { const today = new Date ( ) ; if ( props . initialMonth != null ) { return props . initialMonth ; } else if ( value [ 0 ] != null ) { return DateUtils . clone ( value [ 0 ] ) ; } else if ( value [ 1 ] != null ) { const month = DateUtils . clone ( value [ 1 ] ) ; if ( ! DateUtils . areSameMonth ( month , props . minDate ) ) { month . setMonth ( month . getMonth ( ) - 1 ) ; } return month ; } else if ( DateUtils . isDayInRange ( today , [ props . minDate , props . maxDate ] ) ) { return today ; } else { return DateUtils . getDateBetween ( [ props . minDate , props . maxDate ] ) ; } }