UNPKG

rsuite

Version:

A suite of react components

487 lines (436 loc) 19 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose"; import React, { useCallback, useMemo, useRef, useState } from 'react'; import PropTypes from 'prop-types'; import mapValues from 'lodash/mapValues'; import pick from 'lodash/pick'; import omit from 'lodash/omit'; import IconCalendar from '@rsuite/icons/legacy/Calendar'; import IconClockO from '@rsuite/icons/legacy/ClockO'; import { Calendar, CalendarState } from '../Calendar'; import useCalendarDate from '../Calendar/useCalendarDate'; import Toolbar from './Toolbar'; import { composeFunctions, createChainedFunction, DateUtils, mergeRefs, useClassNames, useControlled, useCustom } from '../utils'; import { PickerOverlay, pickerPropTypes, PickerToggle, PickerToggleTrigger, pickTriggerPropKeys, omitTriggerPropKeys, usePickerClassName, usePublicMethods, useToggleKeyDownEvent } from '../Picker'; import { useCalendarState } from './utils'; var DatePicker = /*#__PURE__*/React.forwardRef(function (props, ref) { var _props$as = props.as, Component = _props$as === void 0 ? 'div' : _props$as, className = props.className, _props$classPrefix = props.classPrefix, classPrefix = _props$classPrefix === void 0 ? 'picker' : _props$classPrefix, calendarDefaultDate = props.calendarDefaultDate, _props$cleanable = props.cleanable, cleanable = _props$cleanable === void 0 ? true : _props$cleanable, defaultValue = props.defaultValue, disabled = props.disabled, _props$format = props.format, formatStr = _props$format === void 0 ? 'yyyy-MM-dd' : _props$format, isoWeek = props.isoWeek, _props$limitEndYear = props.limitEndYear, limitEndYear = _props$limitEndYear === void 0 ? 1000 : _props$limitEndYear, overrideLocale = props.locale, menuClassName = props.menuClassName, _props$appearance = props.appearance, appearance = _props$appearance === void 0 ? 'default' : _props$appearance, _props$placement = props.placement, placement = _props$placement === void 0 ? 'bottomStart' : _props$placement, oneTap = props.oneTap, _props$placeholder = props.placeholder, placeholder = _props$placeholder === void 0 ? '' : _props$placeholder, ranges = props.ranges, valueProp = props.value, showMeridian = props.showMeridian, showWeekNumbers = props.showWeekNumbers, style = props.style, toggleAs = props.toggleAs, caretAsProp = props.caretAs, disabledDateProp = props.disabledDate, renderValue = props.renderValue, onChange = props.onChange, onChangeCalendarDate = props.onChangeCalendarDate, onClean = props.onClean, onClose = props.onClose, onEntered = props.onEntered, onExited = props.onExited, onNextMonth = props.onNextMonth, onOk = props.onOk, onOpen = props.onOpen, onPrevMonth = props.onPrevMonth, onSelect = props.onSelect, onToggleMonthDropdown = props.onToggleMonthDropdown, onToggleTimeDropdown = props.onToggleTimeDropdown, rest = _objectWithoutPropertiesLoose(props, ["as", "className", "classPrefix", "calendarDefaultDate", "cleanable", "defaultValue", "disabled", "format", "isoWeek", "limitEndYear", "locale", "menuClassName", "appearance", "placement", "oneTap", "placeholder", "ranges", "value", "showMeridian", "showWeekNumbers", "style", "toggleAs", "caretAs", "disabledDate", "renderValue", "onChange", "onChangeCalendarDate", "onClean", "onClose", "onEntered", "onExited", "onNextMonth", "onOk", "onOpen", "onPrevMonth", "onSelect", "onToggleMonthDropdown", "onToggleTimeDropdown"]); var _useCustom = useCustom('DatePicker', overrideLocale), locale = _useCustom.locale, formatDate = _useCustom.formatDate, parseDate = _useCustom.parseDate; var _useClassNames = useClassNames(classPrefix), merge = _useClassNames.merge, prefix = _useClassNames.prefix; var _useControlled = useControlled(valueProp, defaultValue), value = _useControlled[0], setValue = _useControlled[1]; var _useCalendarDate = useCalendarDate(valueProp, calendarDefaultDate), calendarDate = _useCalendarDate.calendarDate, setCalendarDate = _useCalendarDate.setCalendarDate; var _useState = useState(), inputState = _useState[0], setInputState = _useState[1]; var _useCalendarState = useCalendarState(), calendarState = _useCalendarState.calendarState, reset = _useCalendarState.reset, openMonth = _useCalendarState.openMonth, openTime = _useCalendarState.openTime; var _useState2 = useState(false), active = _useState2[0], setActive = _useState2[1]; var triggerRef = useRef(null); var rootRef = useRef(null); var targetRef = useRef(null); var overlayRef = useRef(null); usePublicMethods(ref, { rootRef: rootRef, triggerRef: triggerRef, overlayRef: overlayRef, targetRef: targetRef }); /** * Switch to the callback triggered after the next month. */ var handleMoveForward = useCallback(function (nextPageDate) { setCalendarDate(nextPageDate); onNextMonth === null || onNextMonth === void 0 ? void 0 : onNextMonth(nextPageDate); onChangeCalendarDate === null || onChangeCalendarDate === void 0 ? void 0 : onChangeCalendarDate(nextPageDate); }, [onChangeCalendarDate, onNextMonth, setCalendarDate]); /** * Switch to the callback triggered after the previous month. */ var handleMoveBackward = useCallback(function (nextPageDate) { setCalendarDate(nextPageDate); onPrevMonth === null || onPrevMonth === void 0 ? void 0 : onPrevMonth(nextPageDate); onChangeCalendarDate === null || onChangeCalendarDate === void 0 ? void 0 : onChangeCalendarDate(nextPageDate); }, [onChangeCalendarDate, onPrevMonth, setCalendarDate]); /** * The callback triggered when the date changes. */ var handleDateChange = useCallback(function (nextValue, event) { onSelect === null || onSelect === void 0 ? void 0 : onSelect(nextValue, event); onChangeCalendarDate === null || onChangeCalendarDate === void 0 ? void 0 : onChangeCalendarDate(nextValue, event); }, [onChangeCalendarDate, onSelect]); /** * A callback triggered when the time on the calendar changes. */ var handleChangePageTime = useCallback(function (nextPageTime) { setCalendarDate(nextPageTime); handleDateChange(nextPageTime); }, [handleDateChange, setCalendarDate]); var handleClose = useCallback(function () { var _triggerRef$current, _triggerRef$current$c; (_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 ? void 0 : (_triggerRef$current$c = _triggerRef$current.close) === null || _triggerRef$current$c === void 0 ? void 0 : _triggerRef$current$c.call(_triggerRef$current); }, []); /** * The callback triggered when PM/AM is switched. */ var handleToggleMeridian = useCallback(function () { var hours = DateUtils.getHours(calendarDate); var nextHours = hours >= 12 ? hours - 12 : hours + 12; var nextDate = DateUtils.setHours(calendarDate, nextHours); setCalendarDate(nextDate); }, [calendarDate, setCalendarDate]); var updateValue = useCallback(function (event, nextPageDate, closeOverlay) { if (closeOverlay === void 0) { closeOverlay = true; } var nextValue = typeof nextPageDate !== 'undefined' ? nextPageDate : calendarDate; setCalendarDate(nextValue || new Date()); setValue(nextValue); if (nextValue !== value) { onChange === null || onChange === void 0 ? void 0 : onChange(nextValue, event); } // `closeOverlay` default value is `true` if (closeOverlay !== false) { handleClose(); } }, [handleClose, onChange, calendarDate, setCalendarDate, setValue, value]); /** * The callback triggered after the date in the shortcut area is clicked. */ var handleShortcutPageDate = useCallback(function (value, closeOverlay, event) { updateValue(event, value, closeOverlay); handleDateChange(value, event); }, [handleDateChange, updateValue]); /** * The callback triggered after clicking the OK button. */ var handleOK = useCallback(function (event) { updateValue(event); onOk === null || onOk === void 0 ? void 0 : onOk(calendarDate, event); }, [updateValue, onOk, calendarDate]); /** * Toggle month selection panel */ var handleMonthDropdown = useCallback(function () { if (calendarState === CalendarState.DROP_MONTH) { reset(); } else { openMonth(); } onToggleMonthDropdown === null || onToggleMonthDropdown === void 0 ? void 0 : onToggleMonthDropdown(calendarState !== CalendarState.DROP_MONTH); }, [calendarState, onToggleMonthDropdown, openMonth, reset]); /** * Switch time selection panel */ var handleTimeDropdown = useCallback(function () { if (calendarState === CalendarState.DROP_TIME) { reset(); } else { openTime(); } onToggleTimeDropdown === null || onToggleTimeDropdown === void 0 ? void 0 : onToggleTimeDropdown(calendarState !== CalendarState.DROP_TIME); }, [calendarState, onToggleTimeDropdown, openTime, reset]); /** * Callback after clicking the clear button. */ var handleClean = useCallback(function (event) { setCalendarDate(new Date()); updateValue(event, null); }, [setCalendarDate, updateValue]); /** * Handle keyboard events. */ var onPickerKeyDown = useToggleKeyDownEvent(_extends({ triggerRef: triggerRef, targetRef: targetRef, active: active, onExit: handleClean }, rest)); /** * Callback after the date is selected. */ var handleSelect = useCallback(function (nextValue, event, updatableValue) { if (updatableValue === void 0) { updatableValue = true; } setCalendarDate( // Determine whether the current value contains time, if not, use calendarDate. DateUtils.shouldTime(formatStr) ? nextValue : composeFunctions(function (d) { return DateUtils.setHours(d, DateUtils.getHours(calendarDate)); }, function (d) { return DateUtils.setMinutes(d, DateUtils.getMinutes(calendarDate)); }, function (d) { return DateUtils.setSeconds(d, DateUtils.getSeconds(calendarDate)); })(nextValue)); handleDateChange(nextValue); if (oneTap && updatableValue) { updateValue(event, nextValue); } }, [formatStr, handleDateChange, oneTap, calendarDate, setCalendarDate, updateValue]); /** * A callback triggered when the date on the calendar changes. */ var handleChangePageDate = useCallback(function (nextPageDate, event) { setCalendarDate(nextPageDate); reset(); handleDateChange(nextPageDate); // Show only the calendar month panel. formatStr = 'yyyy-MM' var onlyShowMonth = DateUtils.shouldMonth(formatStr) && !DateUtils.shouldDate(formatStr); if (oneTap && onlyShowMonth) { updateValue(event, nextPageDate); } }, [formatStr, handleDateChange, oneTap, reset, setCalendarDate, updateValue]); var disabledDate = useCallback(function (date) { var _disabledDateProp; return (_disabledDateProp = disabledDateProp === null || disabledDateProp === void 0 ? void 0 : disabledDateProp(date)) !== null && _disabledDateProp !== void 0 ? _disabledDateProp : false; }, [disabledDateProp]); /** * Callback after the input box value is changed. */ var handleInputChange = useCallback(function (value, event) { setInputState('Typing'); // isMatch('01/11/2020', 'MM/dd/yyyy') ==> true // isMatch('2020-11-01', 'MM/dd/yyyy') ==> false if (!DateUtils.isMatch(value, formatStr, { locale: locale.dateLocale })) { setInputState('Error'); return; } var date = parseDate(value, formatStr); // If only the time is included in the characters, it will default to today. if (DateUtils.shouldOnlyTime(formatStr)) { date = new Date(DateUtils.format(new Date(), 'yyyy-MM-dd') + " " + value); } if (!DateUtils.isValid(date)) { setInputState('Error'); return; } if (disabledDate(date)) { setInputState('Error'); return; } handleSelect(date, event, false); }, [formatStr, locale, parseDate, disabledDate, handleSelect]); /** * The callback after the enter key is triggered on the input */ var handleInputPressEnd = useCallback(function (event) { if (inputState === 'Typing') { updateValue(event, calendarDate); } setInputState('Initial'); }, [inputState, calendarDate, updateValue]); var handleEntered = useCallback(function () { onOpen === null || onOpen === void 0 ? void 0 : onOpen(); setActive(true); }, [onOpen]); var handleExited = useCallback(function () { onClose === null || onClose === void 0 ? void 0 : onClose(); reset(); setActive(false); }, [onClose, reset]); // Check whether the time is within the time range of the shortcut option in the toolbar. var disabledToolbarHandle = useCallback(function (date) { var _disabledDateProp2; var allowDate = (_disabledDateProp2 = disabledDateProp === null || disabledDateProp === void 0 ? void 0 : disabledDateProp(date)) !== null && _disabledDateProp2 !== void 0 ? _disabledDateProp2 : false; var allowTime = DateUtils.disabledTime(props, date); return allowDate || allowTime; }, [disabledDateProp, props]); var calendarProps = useMemo(function () { return mapValues(pick(props, DateUtils.calendarOnlyProps), function (disabledOrHiddenTimeFunc) { return function (next, date) { var _disabledOrHiddenTime; return (_disabledOrHiddenTime = disabledOrHiddenTimeFunc === null || disabledOrHiddenTimeFunc === void 0 ? void 0 : disabledOrHiddenTimeFunc(next, date)) !== null && _disabledOrHiddenTime !== void 0 ? _disabledOrHiddenTime : false; }; }); }, [props]); var inSameMonth = useCallback(function (date) { return DateUtils.isSameMonth(date, calendarDate); }, [calendarDate]); var calendar = /*#__PURE__*/React.createElement(Calendar, _extends({}, calendarProps, { locale: locale, showWeekNumbers: showWeekNumbers, showMeridian: showMeridian, disabledDate: disabledDate, limitEndYear: limitEndYear, format: formatStr, isoWeek: isoWeek, inSameMonth: inSameMonth, calendarState: calendarState, calendarDate: calendarDate, onMoveForward: handleMoveForward, onMoveBackward: handleMoveBackward, onSelect: handleSelect, onToggleMonthDropdown: handleMonthDropdown, onToggleTimeDropdown: handleTimeDropdown, onChangePageDate: handleChangePageDate, onChangePageTime: handleChangePageTime, onToggleMeridian: handleToggleMeridian })); var renderDropdownMenu = function renderDropdownMenu(positionProps, speakerRef) { var left = positionProps.left, top = positionProps.top, className = positionProps.className; var classes = merge(menuClassName, className, prefix('date-menu')); var styles = { left: left, top: top }; return /*#__PURE__*/React.createElement(PickerOverlay, { role: "dialog", className: classes, ref: mergeRefs(overlayRef, speakerRef), style: styles, target: triggerRef }, calendar, /*#__PURE__*/React.createElement(Toolbar, { locale: locale, ranges: ranges, calendarDate: calendarDate, disabledOkBtn: disabledToolbarHandle, disabledShortcut: disabledToolbarHandle, onClickShortcut: handleShortcutPageDate, onOk: handleOK, hideOkBtn: oneTap })); }; var hasValue = !!value; var _usePickerClassName = usePickerClassName(_extends({}, props, { classPrefix: classPrefix, name: 'date', appearance: appearance, hasValue: hasValue, cleanable: cleanable })), classes = _usePickerClassName[0], usedClassNamePropKeys = _usePickerClassName[1]; var renderDate = useCallback(function () { var _renderValue; if (!value) { return placeholder || formatStr; } return (_renderValue = renderValue === null || renderValue === void 0 ? void 0 : renderValue(value, formatStr)) !== null && _renderValue !== void 0 ? _renderValue : formatDate(value, formatStr); }, [formatStr, formatDate, placeholder, renderValue, value]); var caretAs = useMemo(function () { return caretAsProp || (DateUtils.shouldOnlyTime(formatStr) ? IconClockO : IconCalendar); }, [caretAsProp, formatStr]); return /*#__PURE__*/React.createElement(PickerToggleTrigger, { trigger: "active", pickerProps: pick(props, pickTriggerPropKeys), ref: triggerRef, placement: placement, onEntered: createChainedFunction(handleEntered, onEntered), onExited: createChainedFunction(handleExited, onExited), speaker: renderDropdownMenu }, /*#__PURE__*/React.createElement(Component, { className: merge(className, classes), style: style, ref: rootRef }, /*#__PURE__*/React.createElement(PickerToggle, _extends({}, omit(rest, [].concat(omitTriggerPropKeys, usedClassNamePropKeys, DateUtils.calendarOnlyProps)), { className: prefix({ error: inputState === 'Error' }), as: toggleAs, ref: targetRef, appearance: appearance, input: true, inputValue: value ? formatDate(value, formatStr) : '', inputPlaceholder: typeof placeholder === 'string' && placeholder ? placeholder : formatStr, inputMask: DateUtils.getDateMask(formatStr), onInputChange: handleInputChange, onInputBlur: handleInputPressEnd, onInputPressEnter: handleInputPressEnd, onKeyDown: onPickerKeyDown, onClean: createChainedFunction(handleClean, onClean), cleanable: cleanable && !disabled, hasValue: hasValue, active: active, placement: placement, disabled: disabled, caretAs: caretAs, "aria-haspopup": "dialog" }), renderDate()))); }); DatePicker.displayName = 'DatePicker'; DatePicker.propTypes = _extends({}, pickerPropTypes, { calendarDefaultDate: PropTypes.instanceOf(Date), defaultValue: PropTypes.instanceOf(Date), disabledDate: PropTypes.func, disabledHours: PropTypes.func, disabledMinutes: PropTypes.func, disabledSeconds: PropTypes.func, format: PropTypes.string, hideHours: PropTypes.func, hideMinutes: PropTypes.func, hideSeconds: PropTypes.func, isoWeek: PropTypes.bool, limitEndYear: PropTypes.number, onChange: PropTypes.func, onChangeCalendarDate: PropTypes.func, onNextMonth: PropTypes.func, onOk: PropTypes.func, onPrevMonth: PropTypes.func, onSelect: PropTypes.func, onToggleMonthDropdown: PropTypes.func, onToggleTimeDropdown: PropTypes.func, oneTap: PropTypes.bool, panelContainerRef: PropTypes.any, ranges: PropTypes.array, showMeridian: PropTypes.bool, showWeekNumbers: PropTypes.bool, value: PropTypes.instanceOf(Date) }); export default DatePicker;