UNPKG

semantic-ui-calendar-react

Version:
258 lines (239 loc) 7.27 kB
import React from 'react'; import PropTypes from 'prop-types'; import moment from 'moment'; import _ from 'lodash'; import InputView from '../views/InputView'; import YearPicker from '../pickers/YearPicker'; import MonthPicker from '../pickers/MonthPicker'; import DayPicker from '../pickers/dayPicker/DayPicker'; import HourPicker from '../pickers/timePicker/HourPicker'; import MinutePicker from '../pickers/timePicker/MinutePicker'; import BaseInput from './BaseInput'; import { parseValue, parseArrayOrValue, getInitializer, TIME_FORMAT, chooseValue, } from './parse'; import { getUnhandledProps, tick } from '../lib'; function getNextMode(currentMode) { if (currentMode === 'year') return 'month'; if (currentMode === 'month') return 'day'; if (currentMode === 'day') return 'hour'; if (currentMode === 'hour') return 'minute'; return 'year'; } function getPrevMode(currentMode) { if (currentMode === 'minute') return 'hour'; if (currentMode === 'hour') return 'day'; if (currentMode === 'day') return 'month'; if (currentMode === 'month') return 'year'; return 'minute'; } class DateTimeInput extends BaseInput { constructor(props) { super(props); /* state fields: - mode: one of [ 'year', 'month', 'day', 'hour', 'minute' ] - year: number - month: number - date: number - hour: number - minute: number */ this.state = { mode: props.startMode, }; const parsedValue = parseValue(props.value); if (parsedValue) { this.state.year = parsedValue.year(); this.state.month = parsedValue.month(); this.state.date = parsedValue.date(); this.state.hour = parsedValue.hour(); this.state.minute = parsedValue.minute(); } } getDateParams() { /* Return date params that are used for picker initialization. Return undefined if none of [ 'year', 'month', 'date', 'hour', 'minute' ] state fields defined. */ const { year, month, date, hour, minute, } = this.state; if (!_.isNil(year) || !_.isNil(month) || !_.isNil(date) || !_.isNil(hour) || !_.isNil(minute)) { return { year, month, date, hour, minute }; } } getDateTimeFormat() { const { dateFormat, divider, timeFormat, dateTimeFormat } = this.props; return dateTimeFormat || `${dateFormat}${divider}${TIME_FORMAT[timeFormat]}`; } getPicker({ tabIndex }) { const { value, initialDate, dateFormat, disable, minDate, maxDate, inline, } = this.props; const dateTimeFormat = this.getDateTimeFormat(); const pickerProps = { tabIndex, isPickerInFocus: this.isPickerInFocus, isTriggerInFocus: this.isTriggerInFocus, inline: inline, onCalendarViewMount: this.onCalendarViewMount, closePopup: this.closePopup, displayWeeks: true, hasHeader: true, onChange: this.handleSelect, onHeaderClick: this.switchToPrevMode, initializeWith: getInitializer({ initialDate, dateFormat: dateTimeFormat, dateParams: this.getDateParams() }), value: parseValue(chooseValue(value, initialDate), dateTimeFormat), disable: parseArrayOrValue(disable), minDate: parseValue(minDate, dateFormat), maxDate: parseValue(maxDate, dateFormat), // key: value, // seems like it works without reinstantiating picker every time value changes }; const { mode } = this.state; if (mode === 'year') { return <YearPicker { ...pickerProps } />; } if (mode === 'month') { return <MonthPicker { ...pickerProps } />; } if (mode === 'day') { return <DayPicker { ...pickerProps } />; } if (mode === 'hour') { return <HourPicker timeFormat={ this.props.timeFormat } { ...pickerProps } />; } return <MinutePicker timeFormat={ this.props.timeFormat } { ...pickerProps } />; } _switchToNextModeUndelayed = () => { this.setState(({ mode }) => { return { mode: getNextMode(mode) }; }, this.onModeSwitch); } switchToNextMode = () => { tick(this._switchToNextModeUndelayed); } _switchToPrevModeUndelayed = () => { this.setState(({ mode }) => { return { mode: getPrevMode(mode) }; }, this.onModeSwitch); } switchToPrevMode = () => { tick(this._switchToPrevModeUndelayed); } handleSelect = (e, { value }) => { tick(this._handleSelectUndelayed, e, { value }); } _onFocus = () => { if (!this.props.preserveViewMode) { this.setState({ mode: this.props.startMode }); } } _handleSelectUndelayed = (e, { value }) => { if (this.props.closable && this.state.mode === 'minute') { this.closePopup(); } this.setState(( prevState ) => { const { mode, } = prevState; if (mode === 'minute') { const outValue = moment(value).format(this.getDateTimeFormat()); _.invoke(this.props, 'onChange', e, { ...this.props, value: outValue }); } return { ...value }; }, () => this.state.mode !== 'minute' && this.switchToNextMode()); } render() { const { value, } = this.props; const rest = getUnhandledProps(DateTimeInput, this.props); return ( <InputView popupIsClosed={this.state.popupIsClosed} icon="calendar" onFocus={this._onFocus} onMount={this.onInputViewMount} { ...rest } value={value} render={pickerProps => this.getPicker(pickerProps)} /> ); } } DateTimeInput.propTypes = { /** Currently selected value. */ value: PropTypes.string, /** Moment datetime formatting string */ dateTimeFormat: PropTypes.string, /** Moment date formatting string. */ dateFormat: PropTypes.string, /** Time format ["AMPM", "ampm", "24"] */ timeFormat: PropTypes.string, /** Date to display initially when no date is selected. */ initialDate: PropTypes.oneOfType([ PropTypes.string, PropTypes.instanceOf(moment), PropTypes.instanceOf(Date), ]), /** Date or list of dates that are displayed as disabled. */ disable: PropTypes.oneOfType([ PropTypes.string, PropTypes.arrayOf(PropTypes.string), PropTypes.instanceOf(moment), PropTypes.arrayOf(PropTypes.instanceOf(moment)), PropTypes.instanceOf(Date), PropTypes.arrayOf(PropTypes.instanceOf(Date)), ]), /** Maximum date that can be selected. */ maxDate: PropTypes.oneOfType([ PropTypes.string, PropTypes.instanceOf(moment), PropTypes.instanceOf(Date), ]), /** Minimum date that can be selected. */ minDate: PropTypes.oneOfType([ PropTypes.string, PropTypes.instanceOf(moment), PropTypes.instanceOf(Date), ]), /** Preserve viewmode on focus? */ preserveViewMode: PropTypes.bool, /** Display mode to start. */ startMode: PropTypes.oneOf([ 'year', 'month', 'day', ]), /** Date and time divider. */ divider: PropTypes.string, /** If true, popup closes after selecting a date-time. */ closable: PropTypes.bool, }; DateTimeInput.defaultProps = { dateFormat: 'DD-MM-YYYY', timeFormat: '24', startMode: 'day', divider: ' ', preserveViewMode: true }; export default DateTimeInput;