UNPKG

@e-group/material-lab

Version:

EGroup Team Lab - Incubator for EGroup Team experimental React components.

370 lines (310 loc) 10.4 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _defineProperty from "@babel/runtime/helpers/esm/defineProperty"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } import React, { useEffect, useRef, useState } from 'react'; import { isSameDay, addYears, isAfter, isBefore, format } from 'date-fns'; import { ClickAwayListener, Fade, Popper, TextField, Paper, Hidden, IconButton, createStyles, withStyles } from '@material-ui/core'; import CloseIcon from '@material-ui/icons/Close'; import { getValidDate } from './utils'; import RangeMenu from './RangeMenu'; import Menu from './Menu'; const styles = theme => createStyles({ root: { [theme.breakpoints.down('xs')]: { minWidth: '100vw', minHeight: '100vh', overflow: 'auto', transform: 'none !important' } }, paper: { display: 'flex', [theme.breakpoints.down('xs')]: { width: '100%', minHeight: '100vh' } }, close: { position: 'absolute', right: 5, top: 5 } }); /** * DateRange picker behavior is inspire by ant design. * https://ant.design/components/date-picker/ */ const DateRangePicker = props => { const classes = props.classes, initialStartDate = props.initialStartDate, initialEndDate = props.initialEndDate, minDateProp = props.minDate, maxDateProp = props.maxDate, onChange = props.onChange, onDayClickProp = props.onDayClick, onCloseClick = props.onCloseClick, showTime = props.showTime; const startEl = useRef(null); const endEl = useRef(null); const _useState = useState(false), _useState2 = _slicedToArray(_useState, 2), open = _useState2[0], setOpen = _useState2[1]; const _useState3 = useState(initialStartDate), _useState4 = _slicedToArray(_useState3, 2), startDate = _useState4[0], setStartDate = _useState4[1]; const _useState5 = useState(initialEndDate), _useState6 = _slicedToArray(_useState5, 2), endDate = _useState6[0], setEndDate = _useState6[1]; const _useState7 = useState(''), _useState8 = _slicedToArray(_useState7, 2), startTime = _useState8[0], setStartTime = _useState8[1]; const _useState9 = useState(''), _useState10 = _slicedToArray(_useState9, 2), endTime = _useState10[0], setEndTime = _useState10[1]; const _useState11 = useState(), _useState12 = _slicedToArray(_useState11, 2), hoverDay = _useState12[0], setHoverDay = _useState12[1]; const _useState13 = useState(), _useState14 = _slicedToArray(_useState13, 2), focused = _useState14[0], setFocused = _useState14[1]; const _useState15 = useState({ start: false, end: false }), _useState16 = _slicedToArray(_useState15, 2), touched = _useState16[0], setTouched = _useState16[1]; const minDate = getValidDate(minDateProp, addYears(new Date(), -10)); const maxDate = getValidDate(maxDateProp, addYears(new Date(), 10)); useEffect(() => { const getValidDateTime = (date, time = '00:00') => { if (!date) return undefined; return getValidDate("".concat(format(date, 'yyyy-MM-dd'), " ").concat(time), new Date()); }; if (onChange) { onChange([getValidDateTime(startDate, startTime), getValidDateTime(endDate, endTime)], focused); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [endDate, endTime, focused, startDate, startTime]); const getStartDateTimeValue = () => { if (!startDate) return ''; if (showTime) { return "".concat(format(startDate, 'yyyy-MM-dd'), " ").concat(startTime || '00:00'); } return format(startDate, 'yyyy-MM-dd'); }; const getEndDateTimeValue = () => { if (!endDate) return ''; if (showTime) { return "".concat(format(endDate, 'yyyy-MM-dd'), " ").concat(endTime || '00:00'); } return format(endDate, 'yyyy-MM-dd'); }; const handlePopupOpen = () => { setOpen(true); }; const handlePopupClose = () => { if (onCloseClick) { onCloseClick(); } setOpen(false); setTouched({ start: false, end: false }); }; const focusStartDate = () => { setFocused('start'); const current = startEl.current; if (current) { current.focus(); } }; const focusEndDate = () => { setFocused('end'); const current = endEl.current; if (current) { current.focus(); } }; const handleStartClick = () => { focusStartDate(); handlePopupOpen(); }; const handleEndClick = () => { focusEndDate(); handlePopupOpen(); }; const getDateRangeWhenSetStartDate = day => { const nextStartDate = day; let nextEndDate = endDate; if (day && endDate && isAfter(day, endDate)) { nextEndDate = undefined; } return [nextStartDate, nextEndDate]; }; const getDateRangeWhenSetEndDate = day => { let nextStartDate = startDate; const nextEndDate = day; if (day && startDate && isBefore(day, startDate)) { nextStartDate = undefined; } return [nextStartDate, nextEndDate]; }; // This behavior refer from ant design range picker. const handleSetDateNextAction = (startDate, endDate) => { if (focused === 'start') { setTouched(val => _objectSpread(_objectSpread({}, val), {}, { start: true })); if (!endDate) { focusEndDate(); } else { handlePopupClose(); } } if (focused === 'end') { setTouched(val => _objectSpread(_objectSpread({}, val), {}, { end: true })); if (!startDate) { focusStartDate(); } else { handlePopupClose(); } } }; const handleTimeClick = time => { if (focused === 'start') { setStartTime(time); } if (focused === 'end') { setEndTime(time); } }; const handleMenuConfirmClick = () => { if (focused === 'start') { handleSetDateNextAction(startDate, endDate); } if (focused === 'end') { handleSetDateNextAction(startDate, endDate); } }; const handleMenuDayClick = day => { if (onDayClickProp) { onDayClickProp(day); } if (focused === 'start') { const dateRange = getDateRangeWhenSetStartDate(day); setStartDate(dateRange[0]); setEndDate(dateRange[1]); setStartTime(format(new Date(), 'HH:mm')); if (startTime) { handleSetDateNextAction(dateRange[0], dateRange[1]); } } if (focused === 'end') { const dateRange = getDateRangeWhenSetEndDate(day); setStartDate(dateRange[0]); setEndDate(dateRange[1]); setEndTime(format(new Date(), 'HH:mm')); if (endTime) { handleSetDateNextAction(dateRange[0], dateRange[1]); } } }; const handleRangeMenuDayClick = day => { if (onDayClickProp) { onDayClickProp(day); } if (focused === 'start') { const dateRange = getDateRangeWhenSetStartDate(day); setStartDate(dateRange[0]); setEndDate(dateRange[1]); handleSetDateNextAction(dateRange[0], dateRange[1]); } if (focused === 'end') { const dateRange = getDateRangeWhenSetEndDate(day); setStartDate(dateRange[0]); setEndDate(dateRange[1]); handleSetDateNextAction(dateRange[0], dateRange[1]); } }; const handleDayHover = date => { if (showTime) { if (startDate && !startTime) { return; } if (endDate && !endTime) { return; } } if (!hoverDay || !isSameDay(date, hoverDay)) { setHoverDay(date); } }; return /*#__PURE__*/React.createElement(ClickAwayListener, { onClickAway: handlePopupClose }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(TextField, { inputRef: startEl, label: "startDate", value: getStartDateTimeValue(), onClick: handleStartClick }), /*#__PURE__*/React.createElement(TextField, { inputRef: endEl, label: "endDate", value: getEndDateTimeValue(), onClick: handleEndClick }), /*#__PURE__*/React.createElement(Popper, { open: open, transition: true, anchorEl: startEl.current, className: classes.root }, ({ TransitionProps }) => /*#__PURE__*/React.createElement(Fade, _extends({}, TransitionProps, { timeout: 350 }), /*#__PURE__*/React.createElement(Paper, { className: classes.paper, elevation: 6 }, /*#__PURE__*/React.createElement(Hidden, { smUp: true }, /*#__PURE__*/React.createElement(IconButton, { className: classes.close, onClick: handlePopupClose }, /*#__PURE__*/React.createElement(CloseIcon, null))), showTime ? /*#__PURE__*/React.createElement(Menu, { startDate: startDate, endDate: endDate, minDate: minDate, maxDate: maxDate, hoverDay: hoverDay, touched: touched, focused: focused, onDayClick: handleMenuDayClick, onDayHover: handleDayHover, onTimeClick: handleTimeClick, onConfirmClick: handleMenuConfirmClick, startTime: startTime, endTime: endTime }) : /*#__PURE__*/React.createElement(RangeMenu, { startDate: startDate, endDate: endDate, minDate: minDate, maxDate: maxDate, hoverDay: hoverDay, touched: touched, focused: focused, onDayClick: handleRangeMenuDayClick, onDayHover: handleDayHover })))))); }; export default withStyles(styles, { name: 'EgDateRangePicker' })(DateRangePicker);