UNPKG

bee-datepicker

Version:
376 lines (341 loc) 10.3 kB
import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import KeyCode from 'rc-util/lib/KeyCode'; import { polyfill } from 'react-lifecycles-compat'; import DateTable from './date/DateTable'; import CalendarHeader from './calendar/CalendarHeader'; import CalendarFooter from './calendar/CalendarFooter'; import { calendarMixinWrapper, calendarMixinPropTypes, calendarMixinDefaultProps, getNowByCurrentStateValue, } from './mixin/CalendarMixin'; import { commonMixinWrapper, propType, defaultProp } from './mixin/CommonMixin'; import DateInput from './date/DateInput'; import { getTimeConfig, getTodayTime, syncTime } from './util'; import { goStartMonth, goEndMonth, goTime } from './util/toTime'; import moment from 'moment'; function noop() { } class Calendar extends React.Component { static propTypes = { ...calendarMixinPropTypes, ...propType, prefixCls: PropTypes.string, className: PropTypes.string, style: PropTypes.object, defaultValue: PropTypes.object, value: PropTypes.object, selectedValue: PropTypes.object, defaultSelectedValue: PropTypes.object, mode: PropTypes.oneOf(['time', 'date', 'month', 'year', 'decade']), locale: PropTypes.object, showDateInput: PropTypes.bool, showWeekNumber: PropTypes.bool, showToday: PropTypes.bool, showOk: PropTypes.bool, onSelect: PropTypes.func, onOk: PropTypes.func, onKeyDown: PropTypes.func, timePicker: PropTypes.element, dateInputPlaceholder: PropTypes.any, onClear: PropTypes.func, onChange: PropTypes.func, onPanelChange: PropTypes.func, disabledDate: PropTypes.func, disabledTime: PropTypes.any, dateRender: PropTypes.func, renderFooter: PropTypes.func, renderSidebar: PropTypes.func, clearIcon: PropTypes.node, focusablePanel: PropTypes.bool, } static defaultProps = { ...calendarMixinDefaultProps, ...defaultProp, showToday: true, showDateInput: true, timePicker: null, onOk: noop, onPanelChange: noop, focusablePanel: true, } constructor(props) { super(props); this.state = { mode: this.props.mode || 'date', value: props.value || props.defaultValue || moment(), selectedValue: props.selectedValue || props.defaultSelectedValue, }; } componentDidMount() { if (this.props.showDateInput) { this.saveFocusElement(DateInput.getInstance()); } } onPanelChange = (value, mode) => { const { props, state } = this; if (!('mode' in props)) { this.setState({ mode }); } props.onPanelChange(value || state.value, mode); } onKeyDown = (event) => { if (event.target.nodeName.toLowerCase() === 'input') { return undefined; }else{ this.props.onKeyDown&&this.props.onKeyDown(event); } const keyCode = event.keyCode; // mac const ctrlKey = event.ctrlKey || event.metaKey; const { disabledDate } = this.props; const { value } = this.state; switch (keyCode) { case KeyCode.DOWN: this.goTime(1, 'weeks'); event.preventDefault(); return 1; case KeyCode.UP: this.goTime(-1, 'weeks'); event.preventDefault(); return 1; case KeyCode.LEFT: if (ctrlKey) { this.goTime(-1, 'years'); } else { this.goTime(-1, 'days'); } event.preventDefault(); return 1; case KeyCode.RIGHT: if (ctrlKey) { this.goTime(1, 'years'); } else { this.goTime(1, 'days'); } event.preventDefault(); return 1; case KeyCode.HOME: this.setValue( goStartMonth(this.state.value), ); event.preventDefault(); return 1; case KeyCode.END: this.setValue( goEndMonth(this.state.value), ); event.preventDefault(); return 1; case KeyCode.PAGE_DOWN: this.goTime(1, 'month'); event.preventDefault(); return 1; case KeyCode.PAGE_UP: this.goTime(-1, 'month'); event.preventDefault(); return 1; case KeyCode.ENTER: if (!disabledDate || !disabledDate(value)) { this.onSelect(value, { source: 'keyboard', }); } event.preventDefault(); return 1; } } onClear = () => { this.onSelect(null); this.props.onClear(); } onOk = () => { const { selectedValue } = this.state; if (this.isAllowedDate(selectedValue)) { this.props.onOk(selectedValue); } } onDateInputChange = (value) => { this.onSelect(value, { source: 'dateInput', }); } onDateInputSelect = (value) => { this.onSelect(value, { source: 'dateInputSelect', }); } onDateTableSelect = (value) => { const { timePicker } = this.props; const { selectedValue } = this.state; if (!selectedValue && timePicker) { const timePickerDefaultValue = timePicker.props.defaultValue; if (timePickerDefaultValue) { syncTime(timePickerDefaultValue, value); } } this.onSelect(value); } onToday = () => { const { value } = this.state; const now = getTodayTime(value); this.onSelect(now, { source: 'todayButton', }); } static getDerivedStateFromProps(nextProps, state) { const { value, selectedValue } = nextProps; let newState = {}; if ('mode' in nextProps && state.mode !== nextProps.mode) { newState = { mode: nextProps.mode }; } if ('value' in nextProps) { newState.value = value || nextProps.defaultValue || getNowByCurrentStateValue(state.value); } if ('selectedValue' in nextProps) { newState.selectedValue = selectedValue; } return newState; } getRootDOMNode = () => { return ReactDOM.findDOMNode(this); } openTimePicker = () => { this.onPanelChange(null, 'time'); } closeTimePicker = () => { this.onPanelChange(null, 'date'); } goTime = (direction, unit) => { this.setValue( goTime(this.state.value, direction, unit), ); } onMouseOver = (e) => { e.stopPropagation(); } render() { const { props, state } = this; const { locale, prefixCls, disabledDate, dateInputPlaceholder, timePicker, disabledTime, clearIcon, renderFooter,showMonthInput, renderError, onInputBlur } = props; const { value, selectedValue, mode } = state; const showTimePicker = mode === 'time'; const disabledTimeConfig = showTimePicker && disabledTime && timePicker ? getTimeConfig(selectedValue, disabledTime) : null; let timePickerEle = null; if (timePicker && showTimePicker) { const timePickerProps = { showHour: true, showSecond: true, showMinute: true, ...timePicker.props, ...disabledTimeConfig, onChange: this.onDateInputChange, value: selectedValue, disabledTime, }; if (timePicker.props.defaultValue !== undefined) { timePickerProps.defaultOpenValue = timePicker.props.defaultValue; } timePickerEle = React.cloneElement(timePicker, timePickerProps); } const dateInputElement = props.showDateInput ? ( <DateInput format={this.getFormat()} key="date-input" value={value} locale={locale} placeholder={dateInputPlaceholder} showClear disabledTime={disabledTime} disabledDate={disabledDate} onClear={this.onClear} prefixCls={prefixCls} selectedValue={selectedValue} onChange={this.onDateInputChange} onSelect={this.onDateInputSelect} clearIcon={clearIcon} renderError={renderError} onBlur={onInputBlur} /> ) : null; const children = []; if (props.renderSidebar) { children.push(props.renderSidebar()); } children.push(<div className={`${prefixCls}-panel`} key="panel"> {dateInputElement} <div tabIndex={this.props.focusablePanel ? 0 : undefined} className={`${prefixCls}-date-panel`} onMouseOver={this.onMouseOver} > <CalendarHeader locale={locale} mode={mode} value={value} onValueChange={this.setValue} onPanelChange={this.onPanelChange} renderFooter={renderFooter} showTimePicker={showTimePicker} prefixCls={prefixCls} showMonthInput={showMonthInput} /> {timePicker && showTimePicker ? (<div className={`${prefixCls}-time-picker`}> <div className={`${prefixCls}-time-picker-panel`}> {timePickerEle} </div> </div>) : null} <div className={`${prefixCls}-body`}> <DateTable locale={locale} value={value} selectedValue={selectedValue} prefixCls={prefixCls} dateRender={props.dateRender} onSelect={this.onDateTableSelect} disabledDate={disabledDate} showWeekNumber={props.showWeekNumber} /> </div> <CalendarFooter showOk={props.showOk} mode={mode} renderFooter={props.renderFooter} locale={locale} prefixCls={prefixCls} showToday={props.showToday} disabledTime={disabledTime} showTimePicker={showTimePicker} showDateInput={props.showDateInput} timePicker={timePicker} selectedValue={selectedValue} value={value} disabledDate={disabledDate} okDisabled={ props.showOk !== false && (!selectedValue || !this.isAllowedDate(selectedValue)) } onOk={this.onOk} onSelect={this.onSelect} onToday={this.onToday} onOpenTimePicker={this.openTimePicker} onCloseTimePicker={this.closeTimePicker} /> </div> </div>); return this.renderRoot({ children, className: props.showWeekNumber ? `${prefixCls}-week-number` : '', }); } } polyfill(Calendar); export default calendarMixinWrapper(commonMixinWrapper(Calendar));