UNPKG

bee-datepicker

Version:
227 lines (200 loc) 5.65 kB
import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import { polyfill } from 'react-lifecycles-compat'; import createChainedFunction from 'rc-util/lib/createChainedFunction'; import KeyCode from 'rc-util/lib/KeyCode'; import placements from './picker/placements'; import Trigger from 'rc-trigger'; function noop() { } function refFn(field, component) { this[field] = component; } class Picker extends React.Component { static propTypes = { animation: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), disabled: PropTypes.bool, transitionName: PropTypes.string, onChange: PropTypes.func, onOpenChange: PropTypes.func, children: PropTypes.func, getCalendarContainer: PropTypes.func, calendar: PropTypes.element, style: PropTypes.object, open: PropTypes.bool, defaultOpen: PropTypes.bool, prefixCls: PropTypes.string, placement: PropTypes.any, value: PropTypes.oneOfType([ PropTypes.object, PropTypes.array, ]), defaultValue: PropTypes.oneOfType([ PropTypes.object, PropTypes.array, ]), align: PropTypes.object, } static defaultProps = { prefixCls: 'rc-calendar-picker', style: {}, align: {}, placement: 'bottomLeft', defaultOpen: false, onChange: noop, onOpenChange: noop, } constructor(props) { super(props); let open; if ('open' in props) { open = props.open; } else { open = props.defaultOpen; } const value = props.value || props.defaultValue; this.saveCalendarRef = refFn.bind(this, 'calendarInstance'); this.state = { open, value, }; } componentDidUpdate(_, prevState) { if (!prevState.open && this.state.open) { // setTimeout is for making sure saveCalendarRef happen before focusCalendar this.focusTimeout = setTimeout(this.focusCalendar, 0, this); } } componentWillUnmount() { clearTimeout(this.focusTimeout); } onCalendarKeyDown = (event) => { if (event.keyCode === KeyCode.ESC) { event.stopPropagation(); this.close(this.focus); } this.props.onKeyDown&&this.props.onKeyDown(event); } onCalendarSelect = (value, cause = {}) => { const props = this.props; if (!('value' in props)) { this.setState({ value, }); } if ( cause.source === 'keyboard' || cause.source === 'dateInputSelect' || (!props.calendar.props.timePicker && cause.source !== 'dateInput') || cause.source === 'todayButton') { this.close(this.focus); } props.onChange(value); } onKeyDown = (event) => { if (!this.state.open && (event.keyCode === KeyCode.DOWN || event.keyCode === KeyCode.ENTER)) { this.open(); event.preventDefault(); } this.props.onKeyDown&&this.props.onKeyDown(event); } onCalendarOk = () => { this.close(this.focus); } onCalendarClear = () => { this.close(this.focus); } onVisibleChange = (open) => { this.setOpen(open); } static getDerivedStateFromProps(nextProps) { const newState = {}; const { value, open } = nextProps; if ('value' in nextProps) { newState.value = value; } if (open !== undefined) { newState.open = open; } return newState; } getCalendarElement = () => { const props = this.props; const state = this.state; const calendarProps = props.calendar.props; const { value } = state; const defaultValue = value; const extraProps = { ref: this.saveCalendarRef, defaultValue: defaultValue || calendarProps.defaultValue, selectedValue: value, onKeyDown: this.onCalendarKeyDown, onOk: createChainedFunction(calendarProps.onOk, this.onCalendarOk), onSelect: createChainedFunction(calendarProps.onSelect, this.onCalendarSelect), onClear: createChainedFunction(calendarProps.onClear, this.onCalendarClear), }; return React.cloneElement(props.calendar, extraProps); } setOpen = (open, callback) => { const { onOpenChange } = this.props; if (this.state.open !== open) { if (!('open' in this.props)) { this.setState({ open, }, callback); } onOpenChange(open); } } open = (callback) => { this.setOpen(true, callback); } close = (callback) => { this.setOpen(false, callback); } focus = () => { if (!this.state.open) { ReactDOM.findDOMNode(this).focus(); } } focusCalendar = () => { if (this.state.open && !!this.calendarInstance) { this.calendarInstance.focus(); } } render() { const props = this.props; const { prefixCls, placement, style, getCalendarContainer, align, animation, disabled, dropdownClassName, transitionName, children, } = props; const state = this.state; return ( <Trigger popup={this.getCalendarElement()} popupAlign={align} builtinPlacements={placements} popupPlacement={placement} action={(disabled && !state.open) ? [] : ['click']} destroyPopupOnHide getPopupContainer={getCalendarContainer} popupStyle={style} popupAnimation={animation} popupTransitionName={transitionName} popupVisible={state.open} onPopupVisibleChange={this.onVisibleChange} prefixCls={prefixCls} popupClassName={dropdownClassName} > {React.cloneElement(children(state, props), { onKeyDown: this.onKeyDown })} </Trigger> ); } } polyfill(Picker); export default Picker;