UNPKG

react-date-field

Version:
356 lines (269 loc) 7.16 kB
import React from 'react' import { findDOMNode } from 'react-dom' import Component from 'react-class' import assign from 'object-assign' import { Flex, Item } from 'react-flex' import Input from 'react-field' import toMoment from './toMoment' const notEmpty = (s) => !!s const join = (array) => array.filter(notEmpty).join(' ') const getPicker = (props) => { return React.Children.toArray(props.children).filter(c => c && c.props && c.props.isDatePicker)[0] } export default class DateField extends Component { constructor(props){ super(props) const picker = getPicker(props) || { props: {} } const pickerProps = picker.props const date = pickerProps.defaultDate !== undefined? pickerProps.defaultDate: new Date() this.state = { date, expanded: props.defaultExpanded || false, focused: false } } render(){ const props = this.p = this.prepareProps(this.props) return <Flex inline row {...props} onFocus={this.onFocus} tabIndex={this.state.focused? -1: this.props.tabIndex || 0} > {this.renderInput()} {this.renderClearIcon()} {this.renderCalendarIcon()} {this.renderDatePicker()} </Flex> } renderInput(){ const props = this.p const inputProps = this.prepareInputProps(props) let input if (props.renderInput){ input = props.renderInput(inputProps) } if (input === undefined){ input = <Input {...inputProps} /> } return input } renderClearIcon(){ const props = this.p if (!props.clearIcon){ return } const clearIcon = props.clearIcon === true? '✖': props.clearIcon const clearIconProps = { style: { visibility: props.textValue? 'visible': 'hidden' }, className: 'react-date-field__clear-icon', onMouseDown: this.onClearMouseDown, children: clearIcon } let result if (props.renderClearIcon){ result = props.renderClearIcon(clearIconProps) } if (result === undefined){ result = <span {...clearIconProps} /> } return result } onClearMouseDown(event){ event.preventDefault() this.onPickerChange('', null, event) } renderCalendarIcon(){ let result const renderIcon = this.props.renderCalendarIcon const calendarIconProps = { className: 'react-date-field__calendar-icon', onMouseDown: this.onCalendarIconMouseDown, children: <div className="react-date-field__calendar-icon-inner" /> } if(renderIcon){ result = renderIcon(calendarIconProps) } if(result === undefined){ result = <div {...calendarIconProps} /> } return result } onCalendarIconMouseDown(event){ if (this.state.focused){ event.preventDefault() } this.toggleExpand() } toggleExpand(){ this.setExpanded(!this.p.expanded) } prepareProps(thisProps){ const props = assign({}, thisProps) props.expanded = props.expanded === undefined? this.state.expanded: props.expanded const picker = getPicker(props) || { props: {} } const pickerProps = picker.props this.pickerProps = pickerProps props.locale = pickerProps.locale props.dateFormat = pickerProps.dateFormat props.date = pickerProps.date !== undefined? //we allow null for input date pickerProps.date: this.state.date let date = props.date if (date != null){ date = toMoment(props.date, props.displayFormat || props.dateFormat, { strict: false, locale: props.locale }) if (!date.isValid() && props.displayFormat){ date = toMoment(props.date, props.dateFormat, { strict: false, locale: props.locale }) } } props.date = date props.textValue = date && date.isValid()? date.format(props.displayFormat || props.dateFormat): '' props.className = this.prepareClassName(props) return props } prepareClassName(props){ return join([ 'react-date-field', props.className, this.state.focused? join([ 'react-date-field--focused', props.focusedClassName ]): '' ]) } prepareInputProps(props){ const newInputProps = { ref: 'field', date: props.date, onFocus: this.onFieldFocus, onBlur: this.onFieldBlur, onChange: this.onInputChange, className: join([ 'react-date-field__input', props.inputProps && props.inputProps.className, props.inputClassName ]) } if (props.textValue !== undefined){ newInputProps.value = props.textValue } const inputProps = assign( {}, props.defaultInputProps, props.inputProps, newInputProps ) return inputProps } onFieldFocus(event){ if (this.state.focused){ return } this.setState({ focused: true }) if (this.props.expandOnFocus){ this.setExpanded(true) } this.props.onFocus(event) } onFieldBlur(event){ this.setState({ focused: false }) this.setExpanded(false) this.props.onBlur(event) } renderDatePicker(){ const props = this.p if (props.expanded){ const picker = getPicker(props) if (!picker){ return } return React.cloneElement(picker, { onMouseDown: (event) => { event.preventDefault() }, onChange: this.onPickerChange }) } } onInputChange(value, event){ } setExpanded(bool){ if (bool === this.p.expanded){ return } if (this.props.expanded === undefined){ this.setState({ expanded: bool }) } this.props.onExpandChange(bool) } onPickerChange(dateText, mom, event){ if (this.p.collapseOnChange){ this.setExpanded(false) } const pickerProps = this.pickerProps if (pickerProps.date === undefined){ //the picker is uncontrolled, so also the datefield should be //uncontrolled and reflect the changes this.setState({ date: dateText }) } //call the onChange of the picker! const args = [...arguments] if (pickerProps.onChange){ pickerProps.onChange(...args) } } onFocus(event){ if (this.state.focused){ return } this.focusField() } focusField(){ const input = findDOMNode(this.refs.field); input.focus() } } const emptyFn = () => {} DateField.defaultProps = { expandOnFocus: true, collapseOnChange: true, onChange: emptyFn, onBlur: emptyFn, onFocus: emptyFn, clearIcon: true, onExpandChange: () => {} } DateField.propTypes = { children: function(props, propName){ const picker = React.Children.toArray(props.children).filter(c => c && c.props && c.props.isDatePicker)[0] if (!picker){ return new Error('You should render a "DatePicker" child in the DateField component.') } } }