import { ReactNode , useState } from "react" ; import { CaptionElementProps , Modifier } from "react-day-picker" ; import DayPickerInput from "react-day-picker/DayPickerInput" ; import { Input , InputProps } from "../input/input" ; import { PopoverPane } from "../popover/pane/pane" ; import "./date-input.css" ; import { DateInputFormat , dateInputFormats } from "./format" ; import { DateInputMonth } from "./month/month" ; import { DateInputNavbar } from "./navbar/navbar" ; interface Props { /**
     * Date format of the text box. This is used to display the selected date
     * and to parse the user's input into `Date`. Choose one from
     * `DateInput.formats`. Defaults to "dd/mm/yyyy".
     */ format ? : DateInputFormat ; /**
     * The maximum date users can choose in the pop-up calendar.
     */ maxDate ? : Date ; /**
     * The minimum date users can choose in the pop-up calendar.
     */ minDate ? : Date ; /**
     * Value of the input in controlled mode. Note that it includes "null",
     * to represent the state where the user's input is invalid (e.g.
     * "31/2/1999"). This follows the behavior in HTML.
     */ value ? : Date | null ; /**
     * Handler to set the value in controlled mode. Note that it includes
     * "null". See "value" prop for detail.
     */ setValue ? : ( date : Date | null ) => void ; /**
     * Initial value of the input in uncontrolled mode.
     */ defaultValue ? : Date | null ; /**
     * Whether the input is disabled. This disables the whole input. If you
     * want to disable some days, use "minDate" and "maxDate"
     */ disabled ? : InputProps [ "disabled" ] ; /**
     * Size of the text box. Choose one from `DateInput.sizes`. Same default as
     * the in "Input" component.
     */ size ? : InputProps [ "size" ] ; /**
     * Style of the text box. Choose one from `DateInput.styles`. Same default
     * as in the "Input" component.
     */ style ? : InputProps [ "style" ] ; /**
     * The icon of the text box. See "Icon" page.
     */ icon ? : InputProps [ "icon" ] ; } interface DayPickerOverlayProps { children : ReactNode ; selectedDay : Date ; month : Date ; input : null ; classNames : { container : string ; overlay : string ; overlayWrapper : string ; } ; } interface OverlayProps extends DayPickerOverlayProps { target : HTMLDivElement | null ; } const Overlay = ( props ) : JSX . Element | null => { const { target , children , selectedDay , classNames , month , input , ... rest } = props ; if ( target === null ) return null ; return ( < div { ... rest } > < PopoverPane target = { target } children = { children } / > < /div>); } ; const getValue = ( props ) : Date | undefined => { if ( props . value !== undefined ) { return props . value ?? undefined ; } if ( props . defaultValue !== undefined ) { return props . defaultValue ?? undefined ; } return undefined ; } ; const getDisabledDays = ( props ) : Modifier => { const { minDate : min , maxDate : max } = props ; let days = undefined ; if ( max ) days = { after : max } ; if ( min ) days = { ... days , before : min } ; return days ; } ; /**
 * A date input is a control for users to enter a date, either by typing it or
 * choosing from a pop-up calendar.
 *
 * The Date Input component is based on [React Day Picker][3], as an
 * alternative to the built-in `<Input type="date" />`. It works on
 * [unsupported browsers][2] and can display custom date format (e.g. "dmy" or
 * "mdy"). If you don't need these features, use [Input][1] to have better
 * accessibility support.
 
 * [1]: /docs/components-input--primary#date
 * [2]: https://caniuse.com/input-datetime
 * [3]: https://react-day-picker.js.org
 *
 */ export const DateInput = ( props ) : JSX . Element => { const [ target , setTarget ] = useState < HTMLDivElement | null > ( null ) ; const [ month , setMonth ] = useState < Date > ( ( ) => new Date ( ) ) ; const format = props . format ?? DateInput . formats . dmy ; return ( < div ref = { setTarget } > < DayPickerInput inputProps = { { style : props . style , size : props . size , disabled : props . disabled , icon : props . icon , } } component = { Input } clickUnselectsDay overlayComponent = { ( dayPicker ) => ( < Overlay target = { target } { ... dayPicker } />)} dayPickerProps={{ month : month , navbarElement : DateInputNavbar , captionElement : ( { date } ) => ( < DateInputMonth value = { date } setValue = { setMonth } / > ) , disabledDays : getDisabledDays ( props ) , } } value = { getValue ( props ) } onDayChange = { ( day ) => { if ( props . setValue === undefined ) return ; props . setValue ( day ?? null ) ; } } placeholder = { format . placeholder } formatDate = { format . format } parseDate = { format . parse } / > < /div>); } ; DateInput . formats = dateInputFormats ; DateInput . sizes = Input . sizes ; DateInput . styles = Input . styles ;