bee-datepicker
Version:
DatePicker ui component for react
402 lines (381 loc) • 11.6 kB
JavaScript
/**
* Created by chief on 17/4/6.
*/
import Calendar from "./rc-calendar";
import React, { Component } from "react";
import ReactDOM from 'react-dom';
import { KeyCode } from 'tinper-bee-core';
import Picker from "./rc-calendar/Picker";
import FormControl from "bee-form-control";
import TimePickerPanel from "rc-time-picker/lib/Panel";
import moment from "moment";
import Icon from "bee-icon";
import classnames from 'classnames';
import InputGroup from 'bee-input-group';
import zhCN from "./locale/zh_CN";
import omit from 'omit.js';
const timePickerElement = (
<TimePickerPanel defaultValue={moment(moment().format("HH:mm:ss"), "HH:mm:ss")} />
);
let timerDatePicker = true;
class DatePicker extends Component {
constructor(props, context) {
super(props, context);
let value = props.value && moment(props.value),
defaultValue = props.defaultValue && moment(props.defaultValue);
this.state = {
type: "month",
value: this.initValue(props),
open: props.open||false,
inputValue:this.initValue(props),
showClose:false
};
}
initValue=(props)=>{
let value = props.value || props.defaultValue;
if(value){
if(value.format){
value = value;
}else{
if(moment(value).isValid()){
value = moment(value);
}else{
console.error('value is not in the correct format');
value = ''
}
}
}
return value;
}
componentWillReceiveProps(nextProps) {
if ("value" in nextProps) {
this.setState({
value: this.initValue(nextProps)
});
}
if ("open" in nextProps) {
this.setState({
open: nextProps.open
});
}
if ("renderIcon" in nextProps) {
this.setState({
renderIcon: nextProps.renderIcon
});
}
}
getValue = value =>{
let { format } = this.props;
if(typeof format == 'string'){
return value.format(format)
}else{
return value.format(format[0])
}
}
onChange = value => {
const props = this.props;
this.setState({ value:value });
};
inputFocus=()=>{
const { format } = this.props;
let input = document.querySelector('.rc-calendar-input');
if(input){
if(input.value){
input.select()
}else{
input.focus()
}
input.onkeydown=(e)=>{
if(e.keyCode == KeyCode.DELETE){
input.value = '';
this.props.onChange('','');
}else if(e.keyCode == KeyCode.ESC){
this.setState({
open:false
});
let v = this.state.value;
this.props.onOpenChange(false,v, (v && this.getValue(v)) || '');
ReactDOM.findDOMNode(this.outInput).focus();// 按esc时候焦点回到input输入框
}else if(e.keyCode == KeyCode.ENTER){
let parsed = moment(input.value, format, true);
if(parsed.isValid()){
this.setState({
open:false
});
let v = this.state.value;
this.props.onOpenChange(false,v, (v && this.getValue(v)) || '');
ReactDOM.findDOMNode(this.outInput).focus();
}
}
this.props.onKeyDown&&this.props.onKeyDown(e);
}
}
}
onOpenChange = open => {
const props = this.props;
const self = this;
this.setState({
open
},function(){
if(open){
setTimeout(() => {
self.inputFocus()
}, 0);
}
});
const value = self.state.value;
props.onOpenChange(open,value, (value && this.getValue(value)) || '');
if(open){
setTimeout(()=>{
self.inputFocus()
},200);
}
};
handleCalendarChange = (value) => {
const props = this.props;
this.setState({ value: value,inputValue:(value && this.getValue(value)) || '' });
props.onChange(value, (value && this.getValue(value)) || '');
}
handleChange = value => {
const props = this.props;
this.setState({
value: value && Object.assign(value, {_type:'date'}) || value,
inputValue:(value && this.getValue(value)) || ''
});
if(timerDatePicker){
clearTimeout(this.timerout);
props.onChange(value, (value && this.getValue(value)) || '');
timerDatePicker=false;
this.timerout = window.setTimeout(()=>{
timerDatePicker=true
},300)
}
}
onClick = (e) =>{
const props = this.props;
if(props.keyboardInput)e.stopPropagation();
let value = this.state.value;
if(props.keyboardInput){
props.onClick&&props.onClick(e.nativeEvent,value||null,this.state.inputValue);
}else{
props.onClick&&props.onClick(e.nativeEvent,value||null,(value && this.getValue(value)) || '');
}
}
inputChange = (value,e) => {
if(this.props.keyboardInput)e.stopPropagation();
this.setState({
inputValue:value
});
if(moment(value,this.props.format).isValid()){
this.setState({
value:moment(value,this.props.format)
});
value = moment(value,this.props.format);
this.props.onChange(value, (value && this.getValue(value)) || '');
}else{
this.props.onChange(null,value);
}
}
outInputFocus = (e)=>{
if(this.props.hasOwnProperty('open'))e.stopPropagation();
this.props.outInputFocus&&this.props.outInputFocus(e);
}
iconClick=(e)=>{
this.props.iconClick&&this.props.iconClick(e);
}
outInputKeydown=(e)=>{
if(e.keyCode == KeyCode.DELETE){
this.setState({
inputValue:''
});
this.props.onChange('','');
}else if(e.keyCode == KeyCode.ESC){
this.setState({
open:false
});
let value = this.state.inputValue;
if(moment(value,this.props.format).isValid()){
this.setState({
value:moment(value,this.props.format)
});
value = moment(value,this.props.format);
this.props.onChange(value, (value && this.getValue(value)) || '');
}else{
this.props.onChange(null,value);
}
}
this.props.outInputKeydown&&this.props.outInputKeydown(e);
}
onMouseLeave=(e)=>{
this.setState({
showClose:false
})
}
onMouseEnter=(e)=>{
this.setState({
showClose:true
})
}
clear=(e)=>{
e.stopPropagation();
this.setState({
inputValue:'',
value:''
})
this.props.onChange&&this.props.onChange('','');
}
handleSelect=(value)=>{
this.setState({
value:value
})
this.props.onSelect&&this.props.onSelect(value, (value && this.getValue(value)) || '');
// ReactDOM.findDOMNode(this.outInput).focus()
}
//日期面板中输入框的失焦事件
onDateInputBlur = (e) => {
let input = document.querySelector('.rc-calendar-input');
let value;
if(input) {
value = input.value ? input.value : '';
}
this.props.onDateInputBlur && this.props.onDateInputBlur(e,value);
}
//fix:更改系统时区后,日期框需要触发 onChange 事件
onDateHover = ()=>{
let {format} = this.props;
let {value} = this.state,
newValue = value && this.getValue(value);
let inputValue = this.outInput.state.value;
inputValue = format ? inputValue : ( inputValue && this.getValue(moment(inputValue)) );
if(newValue && inputValue !== newValue) {
this.props.onChange && this.props.onChange(value, newValue || '')
}
}
//阻止组件内部事件冒泡到组件外部容器
stopPropagation = (e) => {
e.stopPropagation();
}
render() {
let state = this.state;
let props = this.props;
const {showClose, defaultPanelShown,onBlur,...others} = props;
let value = state.value;
let pickerChangeHandler = {};
let calendarHandler = {};
const autofocus = this.props.autofocus?{autofocus:'autofocus'}:null;
if (props.showTime) {
calendarHandler = {
// fix https://github.com/ant-design/ant-design/issues/1902
onSelect: this.handleChange
};
} else {
pickerChangeHandler = {
onChange: this.handleChange
};
}
const calendar = (
<Calendar
timePicker={props.showTime ? <TimePickerPanel defaultValue={moment(moment().format("HH:mm:ss"), "HH:mm:ss")} /> : null}
{...props}
onSelect={this.handleSelect}
onChange={this.handleCalendarChange}
value={this.state.value}
onInputBlur={this.onDateInputBlur}
/>
);
let keyboardInputProps = {};
if(props.keyboardInput){
keyboardInputProps.readOnly=false;
keyboardInputProps.onChange=this.inputChange;
keyboardInputProps.value=state.inputValue;
}else{
keyboardInputProps.readOnly=true;
keyboardInputProps.value=(value && this.getValue(value)) || ""
}
let classes = classnames(props.className, "datepicker-container");
return (
<div className={classes} onMouseEnter={this.onDateHover} onClick={this.stopPropagation} onMouseOver={this.stopPropagation}
{...omit(others, [
'onDateInputBlur',
'disabledDate',
'getCalendarContainer',
'showToday',
'renderFooter',
'keyboardInput',
'showDateInput',
'showTime',
'closeIcon',
'renderIcon',
'focusOnOpen',
'defultSelect',
'onOpenChange',
'onChange',
'locale',
'showMonthInput',
'onKeyDown',
'renderError',
'format',
'placeholder'
])}
>
<Picker
animation="slide-up"
{...props}
{...pickerChangeHandler}
onOpenChange={this.onOpenChange}
calendar={calendar}
mode = {'year'}
open={'defaultPanelShown' in props ? defaultPanelShown : this.state.open}
value={state.value}
>
{() => {
return (
<InputGroup simple className="datepicker-input-group"
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}
>
<FormControl
ref = { ref => this.outInput = ref }
disabled={props.disabled}
placeholder={this.props.placeholder}
onClick={ (event) => {this.onClick(event)}}
focusSelect={props.defaultSelected}
onFocus={(v,e)=>{this.outInputFocus(e)}}
onKeyDown={this.outInputKeydown}
{...keyboardInputProps}
{...autofocus}
/>
{
showClose&&this.state.value&&this.state.showClose&&(!props.disabled)?(
<InputGroup.Button shape="border"
onClick={this.clear}>
{ props.closeIcon() }
</InputGroup.Button>
):<InputGroup.Button shape="border"
onClick={(e)=>{props.keyboardInput?this.iconClick(e):''}}>
{ props.renderIcon() }
</InputGroup.Button>
}
</InputGroup>
);
}}
</Picker>
</div>
);
}
}
DatePicker.defaultProps = {
closeIcon:()=><Icon type="uf-close-c"/>,
renderIcon: () => <Icon type="uf-calendar" />,
focusOnOpen:true,
defultSelect:false,
onOpenChange:()=>{},
onChange:()=>{},
locale:zhCN,
showMonthInput:false,
onKeyDown:()=>{},
renderError:()=>{},
showClose:true,
format: "YYYY-MM-DD"
}
export default DatePicker;