import React , { createContext , useState , useContext } from 'react' ; import dayjs from 'dayjs' ; import duration from 'dayjs/plugin/duration' ; import isBetween from 'dayjs/plugin/isBetween' ; dayjs . extend ( duration ) ; dayjs . extend ( isBetween ) ; type D = dayjs . Dayjs ; type SelectedDates = [ ] | [ D ] | [ D , D ] ; type ContextType = { selectedDates : SelectedDates ; selectDate ( date ) : void ; baseMonthFirst : D ; setBaseMonth ( to ) : void ; } ; /****************************************
  DatePicker
*****************************************/ type DatePickerProps = { selectRange ? : boolean ; baseMonth ? : string | number | D | Date | null | undefined ; onSelectDate ? : ( selectedDate : SelectedDates ) => void ; } ; const Context = createContext < ContextType > ( null ! ) ; export const DatePicker = ( { children , selectRange = false , baseMonth , onSelectDate , } ) => { const [ selectedDates , setSelectedDates ] = useState < SelectedDates > ( [ ] ) ; const [ baseMonthFirst , setBaseMonthFirst ] = useState < D > ( ( ) => { return dayjs ( baseMonth || new Date ( ) ) . startOf ( 'month' ) ; } ) ; function selectDate ( date ) { let newSelectedDates = [ ] ; if ( selectRange && selectedDates . length === 1 ) { newSelectedDates = [ selectedDates [ 0 ] , date ] ; } else { newSelectedDates = [ date ] ; } setSelectedDates ( newSelectedDates ) ; onSelectDate ?. ( newSelectedDates ) ; } function setBaseMonth ( to ) { if ( typeof to === 'number' ) { const newBaseMonth = baseMonthFirst . add ( to , 'month' ) ; setBaseMonthFirst ( newBaseMonth ) ; } else { setBaseMonthFirst ( to ) ; } } const context = { selectedDates , selectDate , baseMonthFirst , setBaseMonth , } ; return < Context . Provider value = { context } > { children } < /Context.Provider>; } ; /****************************************
  DatePickerCalendar
*****************************************/ type Offset = - 1 | 0 | 1 ; type DatePickerCalendarProps = { offset ? : Offset ; } ; export function DatePickerCalendar ( { offset = 0 } ) { const { baseMonthFirst , selectDate , selectedDates } = useContext ( Context ) ; const theFirst = offset === 0 ? baseMonthFirst : baseMonthFirst . add ( offset , 'month' ) ; const dayOfWeek = theFirst . day ( ) ; const today = dayjs ( new Date ( ) ) ; const daysInMonth = theFirst . daysInMonth ( ) ; const year = theFirst . year ( ) ; const monthNumber = theFirst . format ( 'MM' ) ; const style = { '--datePickerCalendarBoxOffset' : dayOfWeek + 1 } as React . CSSProperties ; return ( < div data - datepicker - calendar = "" style = { style } > < div data - datepicker - calendar - dayofweek = "" > < div > S < /div> < div > M < /div> < div > T < /div> < div > W < /div> < div > T < /div> < div > F < /div> < div > S < /div> < /div> < div data - datepicker - calendar - boxes = "" > { [ ... Array ( daysInMonth ) . keys ( ) ] . map ( ( n ) => { const day = n + 1 ; const dayPad = day . toString ( ) . padStart ( 2 , '0' ) ; const timeStamp = `${ year }-${ monthNumber }-${ dayPad }` ; const date = dayjs ( timeStamp ) ; const selectedFirst = selectedDates [ 0 ] && date . isSame ( selectedDates [ 0 ] , 'day' ) ; const selectedLast = selectedDates [ 1 ] && date . isSame ( selectedDates [ 1 ] , 'day' ) ; const selected = selectedFirst || selectedLast ; const isToday = today . isSame ( date , 'day' ) ; const isPast = today . isAfter ( date , 'day' ) ; const between = selectedDates . length === 2 && date . isBetween ( selectedDates [ 0 ] , selectedDates [ 1 ] ) ; return ( < button key = { day } data - selected = { selected ? '' : undefined } data - selected - first = { selectedFirst ? '' : undefined } data - selected - last = { selectedLast ? '' : undefined } data - today = { isToday ? '' : undefined } data - past = { isPast ? '' : undefined } data - between = { between ? '' : undefined } onClick = { ( ) => selectDate ( date ) } > < time dateTime = { timeStamp } > { day } < /time> < /button>); } ) } < /div> < /div>); }