import React, { useState } from 'react'; import classnames from 'classnames'; import DayPicker from 'react-day-picker'; import Icons from '../icons'; import colors from '../../variables/colors.json'; import spacing from '../../variables/spacing.json'; import styles from './styles.module.scss'; import moment, { Moment } from 'moment-timezone'; export type CompatibleDateValue = Moment | string | number; export const DatePickerContext = React.createContext(null); // Check if a child element is contained by a parent (for "blur"-ing the whole control) export function elementContains(parent: EventTarget & HTMLElement, child: EventTarget & HTMLElement) { if (!child || !child.parentElement) { return false; } if (child.parentElement === parent) { return true; } return elementContains(parent, child.parentElement); } // Component to render a single focusable date display export function DateDisplay({value, active, onSelect}: { value: CompatibleDateValue, active: boolean, onSelect: (active: boolean) => void, }) { return (
onSelect(!active)} onKeyDown={e => { if (e.key === 'Enter') { onSelect(!active); }}} > {moment(value).format('MMM D, YYYY')}
); } export default function DatePicker({ date, focused, anchor = 'ANCHOR_LEFT', floating = true, arrowLeftDisabled = false, arrowRightDisabled = false, numberOfMonths = 1, onChange, onFocusChange, isOutsideRange, }: { date: CompatibleDateValue, focused?: boolean, anchor?: 'ANCHOR_LEFT' | 'ANCHOR_RIGHT', floating?: boolean, arrowLeftDisabled?: boolean, arrowRightDisabled?: boolean, numberOfMonths?: 1 | 2, onChange: (date: CompatibleDateValue) => void, onFocusChange: (focused: boolean) => void, isOutsideRange?: (date: CompatibleDateValue) => boolean, }) { const [mouseMode, setMouseMode] = useState(true); const [uncontrolledFocus, setUncontrolledFocus] = useState(false); const value = moment(date).toDate(); // Either controlled or uncontrolled "focus" state const focus = focused === undefined ? uncontrolledFocus : focused; const setFocus = onFocusChange === undefined ? setUncontrolledFocus : onFocusChange; function scrubDays(days: number) { const newDate = moment(date).clone().add(days, 'days'); return onChange(newDate); } return {context => (
{ const relatedTarget = e.relatedTarget || document.activeElement; if (!elementContains(e.currentTarget, relatedTarget as EventTarget & HTMLElement)) { setFocus(false); } }} onMouseDown={() => setMouseMode(true)} onKeyDown={() => setMouseMode(false)} >
e.key === 'Enter' && !arrowLeftDisabled && scrubDays(-1)} onClick={() => !arrowLeftDisabled && scrubDays(-1)} >
e.key === 'Enter' && !arrowRightDisabled && scrubDays(1)} onClick={() => !arrowRightDisabled && scrubDays(1)} >
{focus ?
isOutsideRange(moment(day)) : undefined, }} onDayClick={day => { if (!isOutsideRange || !isOutsideRange(moment(day))) { onChange(moment(day)); setFocus(false); } }} />
: null}
)}
}