chore: improve UX of RangePicker (#6200)

* chore: improve UX of RangePicker

* test: fix CI
This commit is contained in:
Benjy Cui 2017-05-22 09:42:04 +08:00 committed by GitHub
parent be238c7887
commit 1dae0b65f2
4 changed files with 49 additions and 9 deletions

View File

@ -33,7 +33,7 @@ function pickerValueAdapter(value?: moment.Moment | moment.Moment[]): moment.Mom
export default class RangePicker extends React.Component<any, any> { export default class RangePicker extends React.Component<any, any> {
static contextTypes = { static contextTypes = {
antLocale: PropTypes.object, antLocale: PropTypes.object,
}; };
static defaultProps = { static defaultProps = {
prefixCls: 'ant-calendar', prefixCls: 'ant-calendar',
@ -56,6 +56,7 @@ export default class RangePicker extends React.Component<any, any> {
this.state = { this.state = {
value, value,
open: props.open, open: props.open,
hoverValue: [],
}; };
} }
@ -78,6 +79,8 @@ export default class RangePicker extends React.Component<any, any> {
this.handleChange([]); this.handleChange([]);
} }
clearHoverValue = () => this.setState({ hoverValue: [] });
handleChange = (value: moment.Moment[]) => { handleChange = (value: moment.Moment[]) => {
const props = this.props; const props = this.props;
if (!('value' in props)) { if (!('value' in props)) {
@ -100,6 +103,8 @@ export default class RangePicker extends React.Component<any, any> {
handleShowDateChange = showDate => this.setState({ showDate }); handleShowDateChange = showDate => this.setState({ showDate });
handleHoverChange = hoverValue => this.setState({ hoverValue });
setValue(value) { setValue(value) {
this.handleChange(value); this.handleChange(value);
if (!this.props.showTime) { if (!this.props.showTime) {
@ -115,7 +120,16 @@ export default class RangePicker extends React.Component<any, any> {
const operations = Object.keys(ranges).map((range) => { const operations = Object.keys(ranges).map((range) => {
const value = ranges[range]; const value = ranges[range];
return <a key={range} onClick={() => this.setValue(value)}>{range}</a>; return (
<a
key={range}
onClick={() => this.setValue(value)}
onMouseEnter={() => this.setState({ hoverValue: value })}
onMouseLeave={this.clearHoverValue}
>
{range}
</a>
);
}); });
return ( return (
<div className={`${prefixCls}-range-quick-selector`}> <div className={`${prefixCls}-range-quick-selector`}>
@ -126,7 +140,7 @@ export default class RangePicker extends React.Component<any, any> {
render() { render() {
const { state, props, context } = this; const { state, props, context } = this;
const { value, showDate, open } = state; const { value, showDate, hoverValue, open } = state;
const localeCode = getLocaleCode(context); const localeCode = getLocaleCode(context);
if (value && localeCode) { if (value && localeCode) {
if (value[0]) { if (value[0]) {
@ -138,9 +152,10 @@ export default class RangePicker extends React.Component<any, any> {
} }
const { const {
disabledDate, disabledTime, showTime, showToday, prefixCls, popupStyle, style,
ranges, prefixCls, popupStyle, disabledDate, disabledTime,
style, onOk, locale, format, showTime, showToday,
ranges, onOk, locale, format,
} = props; } = props;
warning(!('onOK' in props), 'It should be `RangePicker[onOk]`, instead of `onOK`!'); warning(!('onOK' in props), 'It should be `RangePicker[onOk]`, instead of `onOK`!');
@ -182,6 +197,8 @@ export default class RangePicker extends React.Component<any, any> {
onOk={onOk} onOk={onOk}
value={showDate || pickerValueAdapter(props.defaultPickerValue) || pickerValueAdapter(moment())} value={showDate || pickerValueAdapter(props.defaultPickerValue) || pickerValueAdapter(moment())}
onValueChange={this.handleShowDateChange} onValueChange={this.handleShowDateChange}
hoverValue={hoverValue}
onHoverChange={this.handleHoverChange}
showToday={showToday} showToday={showToday}
/> />
); );

View File

@ -41,6 +41,25 @@ describe('RangePicker', () => {
.toMatchSnapshot(); .toMatchSnapshot();
}); });
it('highlight range when hover presetted range', () => {
const wrapper = mount(
<RangePicker
ranges={{
'This Month': [moment(), moment().endOf('month')],
}}
getCalendarContainer={trigger => trigger}
format="YYYY/MM/DD"
open
/>
);
let rangeCalendarWrapper = mount(wrapper.find('Trigger').node.getComponent());
rangeCalendarWrapper.find('.ant-calendar-range-quick-selector a')
.simulate('mouseEnter');
rangeCalendarWrapper = mount(wrapper.find('Trigger').node.getComponent());
expect(rangeCalendarWrapper.find('.ant-calendar-selected-day').length).toBe(2);
});
// issue: https://github.com/ant-design/ant-design/issues/5872 // issue: https://github.com/ant-design/ant-design/issues/5872
it('should not throw error when value is reset to `[]`', () => { it('should not throw error when value is reset to `[]`', () => {
const birthday = moment('2000-01-01', 'YYYY-MM-DD'); const birthday = moment('2000-01-01', 'YYYY-MM-DD');

View File

@ -65,11 +65,13 @@ describe('RangePicker with showTime', () => {
<RangePicker showTime open onChange={onChangeFn} onOpenChange={onOpenChangeFn} /> <RangePicker showTime open onChange={onChangeFn} onOpenChange={onOpenChangeFn} />
); );
const calendarWrapper = mount(wrapper.find('Trigger').node.getComponent()); let calendarWrapper = mount(wrapper.find('Trigger').node.getComponent());
expect(calendarWrapper.find('.ant-calendar-time-picker-btn').hasClass('ant-calendar-time-picker-btn-disabled')).toBe(true); expect(calendarWrapper.find('.ant-calendar-time-picker-btn').hasClass('ant-calendar-time-picker-btn-disabled')).toBe(true);
expect(calendarWrapper.find('.ant-calendar-ok-btn').hasClass('ant-calendar-ok-btn-disabled')).toBe(true); expect(calendarWrapper.find('.ant-calendar-ok-btn').hasClass('ant-calendar-ok-btn-disabled')).toBe(true);
calendarWrapper.find('.ant-calendar-date').at(10).simulate('click'); calendarWrapper.find('.ant-calendar-date').at(10).simulate('click');
calendarWrapper = mount(wrapper.find('Trigger').node.getComponent()); // !!! TODO: calendarWrapper cannot get the latest state from wrapper
calendarWrapper.find('.ant-calendar-date').at(11).simulate('click'); calendarWrapper.find('.ant-calendar-date').at(11).simulate('click');
calendarWrapper = mount(wrapper.find('Trigger').node.getComponent()); // !!!
expect(calendarWrapper.find('.ant-calendar-time-picker-btn').hasClass('ant-calendar-time-picker-btn-disabled')).toBe(false); expect(calendarWrapper.find('.ant-calendar-time-picker-btn').hasClass('ant-calendar-time-picker-btn-disabled')).toBe(false);
expect(calendarWrapper.find('.ant-calendar-ok-btn').hasClass('ant-calendar-ok-btn-disabled')).toBe(false); expect(calendarWrapper.find('.ant-calendar-ok-btn').hasClass('ant-calendar-ok-btn-disabled')).toBe(false);
expect(onChangeFn).toHaveBeenCalled(); expect(onChangeFn).toHaveBeenCalled();
@ -84,9 +86,11 @@ describe('RangePicker with showTime', () => {
<RangePicker showTime open onOk={onOkFn} onChange={onChangeFn} onOpenChange={onOpenChangeFn} /> <RangePicker showTime open onOk={onOkFn} onChange={onChangeFn} onOpenChange={onOpenChangeFn} />
); );
const calendarWrapper = mount(wrapper.find('Trigger').node.getComponent()); let calendarWrapper = mount(wrapper.find('Trigger').node.getComponent());
calendarWrapper.find('.ant-calendar-date').at(10).simulate('click'); calendarWrapper.find('.ant-calendar-date').at(10).simulate('click');
calendarWrapper = mount(wrapper.find('Trigger').node.getComponent()); // !!!
calendarWrapper.find('.ant-calendar-date').at(11).simulate('click'); calendarWrapper.find('.ant-calendar-date').at(11).simulate('click');
calendarWrapper = mount(wrapper.find('Trigger').node.getComponent()); // !!!
onChangeFn.mockClear(); onChangeFn.mockClear();
calendarWrapper.find('.ant-calendar-ok-btn').simulate('click'); calendarWrapper.find('.ant-calendar-ok-btn').simulate('click');
expect(onOkFn).toHaveBeenCalled(); expect(onOkFn).toHaveBeenCalled();

View File

@ -45,7 +45,7 @@
"omit.js": "^0.1.0", "omit.js": "^0.1.0",
"prop-types": "^15.5.7", "prop-types": "^15.5.7",
"rc-animate": "~2.3.0", "rc-animate": "~2.3.0",
"rc-calendar": "~8.2.0", "rc-calendar": "~8.3.0",
"rc-cascader": "~0.11.0", "rc-cascader": "~0.11.0",
"rc-checkbox": "~2.0.0", "rc-checkbox": "~2.0.0",
"rc-collapse": "~1.7.0", "rc-collapse": "~1.7.0",