UNPKG

react-date-picker

Version:

A carefully crafted date picker for React

324 lines (249 loc) 6.82 kB
import React from 'react' import { findDOMNode } from 'react-dom' import Component from 'react-class' import assign from 'object-assign' import times from './utils/times' import join from './join' import toMoment from './toMoment' import { Flex, Item } from 'react-flex' import bemFactory from './bemFactory' const bem = bemFactory('react-date-picker__year-view') import { prepareDateProps, getInitialState, onKeyDown, onViewDateChange, onActiveDateChange, onChange, navigate, select, confirm, gotoViewDate } from './DecadeView' const NAV_KEYS = { ArrowUp(mom) { if (mom.get('month') >= 4) { mom.add(-4, 'month') } return mom }, ArrowDown(mom) { if (mom.get('month') <= 7) { mom.add(4, 'month') } return mom }, ArrowLeft(mom) { if (mom.get('month') >= 1) { mom.add(-1, 'month') } return mom }, ArrowRight(mom) { if (mom.get('month') <= 10) { mom.add(1, 'month') } return mom }, Home(mom) { return mom.startOf('year').startOf('month') }, End(mom) { return mom.endOf('year').startOf('month') }, PageUp(mom) { const month = mom.get('month') - 4 const extra4 = month - 4 if (month >= 0) { if (extra4 >= 0) { return mom.set('month', extra4) } return mom.set('month', month) } return mom }, PageDown(mom) { const month = mom.get('month') + 4 const extra4 = month + 4 if (month <= 11) { if (extra4 <= 11) { return mom.set('month', extra4) } return mom.set('month', month) } return mom } } export default class YearView extends Component { constructor(props) { super(props) this.state = getInitialState(props) } /** * Returns all the days in the specified month. * * @param {Moment/Date/Number} value * @return {Moment[]} */ getMonthsInYear(value) { const start = this.toMoment(value).startOf('year') return times(12).map(i => this.toMoment(start).add(i, 'month')) } toMoment(date) { return toMoment(date, this.props) } render() { const props = this.p = assign({}, this.props) if (props.onlyCompareMonth) { // props.adjustDateStartOf = null } const dateProps = prepareDateProps(props, this.state) assign(props, dateProps) const className = join( props.className, bem(), props.theme && bem(null, `theme-${props.theme}`) ) const monthsInView = this.getMonthsInYear(props.viewMoment) const flexProps = assign({}, props) delete flexProps.activeDate delete flexProps.activeMoment delete flexProps.adjustDateStartOf delete flexProps.adjustMaxDateStartOf delete flexProps.adjustMinDateStartOf delete flexProps.cleanup delete flexProps.constrainViewDate delete flexProps.date delete flexProps.dateFormat delete flexProps.isYearView delete flexProps.maxConstrained delete flexProps.maxDate delete flexProps.maxDateMoment delete flexProps.minConstrained delete flexProps.minDate delete flexProps.minDateMoment delete flexProps.moment delete flexProps.monthFormat delete flexProps.navKeys delete flexProps.onActiveDateChange delete flexProps.onViewDateChange delete flexProps.onlyCompareMonth delete flexProps.timestamp delete flexProps.theme delete flexProps.viewDate delete flexProps.viewMoment if (typeof props.cleanup == 'function') { props.cleanup(flexProps) } return <Flex inline column alignItems="stretch" tabIndex={0} {...flexProps} onKeyDown={this.onKeyDown} className={className} > {this.renderMonths(props, monthsInView)} </Flex> } renderMonths(props, months) { const nodes = months.map(monthMoment => this.renderMonth(props, monthMoment)) const buckets = times(Math.ceil(nodes.length / 4)).map(i => { return nodes.slice(i * 4, (i + 1) * 4) }) const className = bem('row') return buckets.map((bucket, i) => <Flex alignItems="center" flex row inline key={`row_${i}`} className={className} > {bucket} </Flex>) } format(mom, format) { format = format || this.props.monthFormat return mom.format(format) } renderMonth(props, dateMoment) { const index = dateMoment.get('month') const monthText = props.monthNames ? props.monthNames[index] || this.format(dateMoment) : this.format(dateMoment) const timestamp = +dateMoment const isActiveDate = props.onlyCompareMonth && props.activeMoment ? dateMoment.get('month') == props.activeMoment.get('month') : timestamp === props.activeDate const isValue = props.onlyCompareMonth && props.moment ? dateMoment.get('month') == props.moment.get('month') : timestamp === props.timestamp const disabled = props.minDate != null && timestamp < props.minDate || props.maxDate != null && timestamp > props.maxDate const className = join( bem('month'), !disabled && isActiveDate && bem('month', 'active'), isValue && bem('month', 'value'), disabled && bem('month', 'disabled') ) const onClick = disabled ? null : this.handleClick.bind(this, { dateMoment, timestamp }) return <Item key={monthText} className={className} onClick={onClick} > {monthText} </Item> } handleClick({ timestamp, dateMoment }, event) { event.target.value = timestamp this.select({ dateMoment, timestamp }, event) } onKeyDown(event) { return onKeyDown.call(this, event) } confirm(date, event) { return confirm.call(this, date, event) } navigate(direction, event) { return navigate.call(this, direction, event) } select({ dateMoment, timestamp }, event) { return select.call(this, { dateMoment, timestamp }, event) } onViewDateChange({ dateMoment, timestamp }) { return onViewDateChange.call(this, { dateMoment, timestamp }) } gotoViewDate({ dateMoment, timestamp }) { return gotoViewDate.call(this, { dateMoment, timestamp }) } onActiveDateChange({ dateMoment, timestamp }) { return onActiveDateChange.call(this, { dateMoment, timestamp }) } onChange({ dateMoment, timestamp }, event) { return onChange.call(this, { dateMoment, timestamp }, event) } focus() { findDOMNode(this).focus() } } YearView.defaultProps = { isYearView: true, navKeys: NAV_KEYS, constrainViewDate: true, theme: 'default', monthFormat: 'MMM', dateFormat: 'YYYY-MM-DD', onlyCompareMonth: true, adjustDateStartOf: 'month', adjustMinDateStartOf: 'month', adjustMaxDateStartOf: 'month' }