DatePicker 组件优化

+ DatePicker showTime: 面板上的日期展示输入框统一为一个,格式和外面的输入框同步,并且支持手动修改。
 面板上的 TimePicker
 + DatePicker showTime: 输入框不再展示,改造为『选择时间』,点击后不再展开浮层,直接盖住日期区域。
 + RangePicker showTime : 只选中开始日期,“确定”和“选择时间”灰置。 如未选择日期直接选择时间,开始日期和结束日期默认选中当天。
 + RangePicker showTime : 点击框外和确定均为确定操作。
 + RangePicker showTime : 在时间页面,开始时间的默认状态为当前时间,结束时间的默认状态跟随开始时间。
 + RangePicker showTime : 开始时间的选择范围没有限制,结束时间的选择范围必须大于等于开始时间。
 + RangePicker showTime : 当开始时间选择了结束时间之后的时间(发生冲突),结束时间则自动切换到与开始时间相同的时间。
This commit is contained in:
RaoHai 2016-07-18 16:44:30 +08:00
parent 3342aae9f3
commit 7dd4a019d5
9 changed files with 367 additions and 42 deletions

View File

@ -78,7 +78,9 @@ export default class RangePicker extends React.Component {
onOk: this.handleChange,
};
if (props.timePicker) {
pickerChangeHandler = {};
pickerChangeHandler.onChange = (value) => {
this.handleChange(value);
};
} else {
calendarHandler = {};
}
@ -91,6 +93,7 @@ export default class RangePicker extends React.Component {
const calendar = (
<RangeCalendar
prefixCls="ant-calendar"
formatter={props.getFormatter()}
className={calendarClassName}
timePicker={props.timePicker}
disabledDate={disabledDate}

View File

@ -29,7 +29,7 @@ const DateRange = React.createClass({
if (!startValue || !this.state.endValue) {
return false;
}
return startValue.getTime() >= this.state.endValue.getTime();
return startValue.getTime() > this.state.endValue.getTime();
},
disabledEndDate(endValue) {
if (!endValue || !this.state.startValue) {
@ -38,7 +38,6 @@ const DateRange = React.createClass({
return endValue.getTime() <= this.state.startValue.getTime();
},
onChange(field, value) {
console.log(field, 'change', value);
this.setState({
[field]: value,
});

View File

@ -9,7 +9,7 @@ const DatePicker = wrapPicker(createPicker(RcCalendar));
const MonthPicker = wrapPicker(createPicker(MonthCalendar), 'yyyy-MM');
DatePicker.Calendar = Calendar;
DatePicker.RangePicker = wrapPicker(RangePicker, 'yyyy-MM-dd');
DatePicker.RangePicker = wrapPicker(RangePicker);
DatePicker.MonthPicker = MonthPicker;
export default DatePicker;

View File

@ -106,7 +106,7 @@
.calendarPanelHeader(@calendar-prefix-cls);
}
&-calendar-body {
&-body {
padding: 4px 8px;
}
@ -163,6 +163,10 @@
text-align: center;
transition: background 0.3s ease;
&-panel {
position: relative;
}
&:hover {
background: tint(@primary-color, 90%);
cursor: pointer;
@ -286,6 +290,9 @@
&-disabled {
.button-color(@btn-disable-color; @btn-disable-bg; @btn-disable-border);
cursor: not-allowed;
&:hover {
.button-color(@btn-disable-color; @btn-disable-bg; @btn-disable-border);
}
}
}
}

View File

@ -26,16 +26,40 @@
width: 470px;
overflow: hidden;
.@{calendar-prefix-cls}-date-panel {
&::after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
}
&-part {
width: 50%;
position: relative;
}
&-left {
float: left;
.@{calendar-prefix-cls} {
&-time-picker-inner {
border-right: 1px solid #e9e9e9;
}
}
}
&-right {
float: right;
.@{calendar-prefix-cls} {
&-time-picker-inner {
margin-left: 21px;
border-left: 1px solid #e9e9e9;
}
&-time-picker-panel {
// padding-left: 22px;
}
}
}
&-middle {
@ -74,7 +98,12 @@
.input;
border-radius: @border-radius-sm;
height: @input-height-sm;
width: 96px;
border: 0;
box-shadow: none;
&:focus {
box-shadow: none;
}
}
.@{timepicker-prefix-cls}-icon {
display: none;
@ -132,14 +161,68 @@
&-bottom {
text-align: right;
}
.@{calendar-prefix-cls}-ok-btn {
position: static;
height: 22px;
margin: 8px;
.@{calendar-prefix-cls} {
&-header {
border-bottom: 0;
}
&-body {
border-top: 1px solid #e9e9e9;
}
}
.@{calendar-prefix-cls}-today-btn {
margin: 8px 12px;
height: 22px;
line-height: 22px;
&.@{calendar-prefix-cls}-time {
.@{timepicker-prefix-cls} {
height: 207px;
top: 68px;
z-index: 2; // in order to cover .ant-calendar-range .ant-calendar-in-range-cell > div (z-index: 1)
&-panel {
height: 241px;
margin-top: -34px;
}
&-inner {
padding-top: 34px;
height: 241px;
background: none;
}
&-combobox {
display: inline-block;
background-color: white;
border-top: 1px solid #e9e9e9;
}
&-select {
width: 71px;
ul {
max-height: 206px;
}
}
}
.@{calendar-prefix-cls}-footer-btn {
padding-right: 12px;
display: block;
&::after {
content: 'x';
height: 0;
font-size: 0;
overflow: hidden;
clear: both;
}
}
.@{calendar-prefix-cls}-ok-btn {
position: static;
height: 22px;
}
.@{calendar-prefix-cls}-footer .@{calendar-prefix-cls}-time-picker-btn {
margin-right: 12px;
}
.@{calendar-prefix-cls}-today-btn {
margin: 8px 12px;
height: 22px;
line-height: 22px;
}
}
}

View File

@ -1,32 +1,264 @@
.@{calendar-prefix-cls}-time {
// Change display order in DOM
.@{calendar-prefix-cls}-input-wrap {
direction: rtl;
.@{calendar-prefix-cls}-date-input-wrap,
.@{calendar-prefix-cls}-time-picker-wrap {
direction: ltr;
display: inline-block;
.@{timepicker-prefix-cls} {
position: absolute;
width: 100%;
top: 34px;
background-color: white;
height: 206px;
&-panel {
z-index: @zindex-picker;
position: absolute;
width: 100%;
}
&-inner {
display: inline-block;
position: relative;
outline: none;
list-style: none;
font-size: 12px;
text-align: left;
background-color: #fff;
background-clip: padding-box;
line-height: 1.5;
overflow: hidden;
}
&-input {
margin: 0;
padding: 0;
border: 0;
width: 100%;
cursor: auto;
line-height: 1.5;
outline: 0;
&-wrap {
display: none;
box-sizing: border-box;
position: relative;
padding: 6px;
border-bottom: 1px solid @border-color-split;
}
.@{timepicker-prefix-cls}-panel,
.@{calendar-prefix-cls}-clear-btn {
direction: ltr;
&-invalid {
border-color: red;
}
}
.@{calendar-prefix-cls}-input,
.@{timepicker-prefix-cls}-input {
.input;
border-radius: @border-radius-sm;
height: @input-height-sm;
width: 96px;
margin-right: 6px;
&-clear-btn {
position: absolute;
right: 5px;
cursor: pointer;
overflow: hidden;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
top: 5px;
margin: 0;
}
.@{calendar-prefix-cls}-input {
padding-right: 21px;
&-clear-btn:after {
content: "\e631";
font-family: "anticon";
font-size: 12px;
color: #ccc;
display: inline-block;
line-height: 1;
width: 20px;
transition: color 0.3s ease;
}
.@{timepicker-prefix-cls}-panel {
min-width: 168px;
&-clear-btn:hover:after {
color: #999;
}
.@{timepicker-prefix-cls}-icon {
display: none;
&-narrow &-input-wrap {
max-width: 111px;
}
&-select {
float: left;
font-size: 12px;
border: 1px solid @border-color-split;
border-width: 0 1px;
margin-left: -1px;
box-sizing: border-box;
width: 77px;
overflow: hidden;
position: relative; // Fix chrome weird render bug
&:hover {
overflow-y: auto;
}
&:first-child {
border-left: 0;
margin-left: 0;
}
&:last-child {
border-right: 0;
}
ul {
list-style: none;
box-sizing: border-box;
margin: 0;
padding: 0;
width: 100%;
max-height: 206px;
}
li {
text-align: center;
list-style: none;
box-sizing: content-box;
margin: 0;
width: 100%;
height: 24px;
line-height: 24px;
cursor: pointer;
user-select: none;
transition: background 0.3s ease;
}
li:last-child:after {
content: '';
height: 120px;
display: block;
}
li:hover {
background: tint(@primary-color, 90%);
}
li&-option-selected {
background: #f7f7f7;
font-weight: bold;
}
li&-option-disabled {
color: @btn-disable-color;
&:hover {
background: transparent;
cursor: @cursor-disabled;
}
}
}
&.slide-up-enter.slide-up-enter-active&-placement-topLeft,
&.slide-up-enter.slide-up-enter-active&-placement-topRight,
&.slide-up-appear.slide-up-appear-active&-placement-topLeft,
&.slide-up-appear.slide-up-appear-active&-placement-topRight {
animation-name: antSlideDownIn;
}
&.slide-up-enter.slide-up-enter-active&-placement-bottomLeft,
&.slide-up-enter.slide-up-enter-active&-placement-bottomRight,
&.slide-up-appear.slide-up-appear-active&-placement-bottomLeft,
&.slide-up-appear.slide-up-appear-active&-placement-bottomRight {
animation-name: antSlideUpIn;
}
&.slide-up-leave.slide-up-leave-active&-placement-topLeft,
&.slide-up-leave.slide-up-leave-active&-placement-topRight {
animation-name: antSlideDownOut;
}
&.slide-up-leave.slide-up-leave-active&-placement-bottomLeft,
&.slide-up-leave.slide-up-leave-active&-placement-bottomRight {
animation-name: antSlideUpOut;
}
}
.@{timepicker-prefix-cls} {
display: inline-block;
outline: none;
font-size: @font-size-base;
&-input {
.input;
width: 100px;
}
&-large &-input {
.input-lg;
}
&-small &-input {
.input-sm;
}
&-open {
opacity: 0;
}
&-icon {
position: absolute;
user-select: none;
transition: all .3s @ease-in-out;
width: 12px;
height: 12px;
line-height: 12px;
right: 8px;
color: #999;
top: 50%;
margin-top: -6px;
&:after {
content: "\e643";
font-family: "anticon";
font-size: 12px;
color: #999;
display: inline-block;
line-height: 1;
vertical-align: bottom;
}
}
}
.@{calendar-prefix-cls} {
&-time {
.@{calendar-prefix-cls}-day-select {
padding: 0 2px;
font-weight: bold;
display: inline-block;
color: #666;
line-height: 34px;
}
.@{calendar-prefix-cls}-footer {
border-top: 1px solid #ccc;
padding: 10px 0;
text-align: right;
position: relative;
height: auto;
line-height: auto;
&-btn {
line-height: 1.5;
text-align: right;
}
.@{calendar-prefix-cls}-today-btn {
float: left;
margin: 0;
padding-left: 12px;
}
.@{calendar-prefix-cls}-time-picker-btn {
display: inline-block;
text-align: center;
margin-right: 60px;
&-disabled {
color: #ccc
}
}
}
}
}

View File

@ -4,7 +4,7 @@
@import "../../button/style/mixin";
@calendar-prefix-cls: ant-calendar;
@timepicker-prefix-cls: ant-time-picker;
@timepicker-prefix-cls: ant-calendar-time-picker;
@import "Picker";
@import "Calendar";

View File

@ -1,6 +1,6 @@
import { PropTypes } from 'react';
import * as React from 'react';
import TimePicker from 'rc-time-picker';
import TimePickerPanel from 'rc-time-picker/lib/module/Panel';
import DateTimeFormat from 'gregorian-calendar-format';
import GregorianCalendar from 'gregorian-calendar';
import classNames from 'classnames';
@ -87,10 +87,10 @@ export default function wrapPicker(Picker, defaultFormat) {
showHour: timeFormat && timeFormat.indexOf('HH') >= 0,
};
const timePicker = props.showTime ? (
<TimePicker
<TimePickerPanel
{...rcTimePickerProps}
{...props.showTime}
prefixCls="ant-time-picker"
prefixCls="ant-calendar-time-picker"
placeholder={locale.timePickerLocale.placeholder}
locale={locale.timePickerLocale}
transitionName="slide-up"

View File

@ -1,3 +1,4 @@
import * as React from 'react';
import { Component, PropTypes } from 'react';
import classNames from 'classnames';
import calculateNodeHeight from './calculateNodeHeight';