Time picker allow clear (#14490)

close #14472
This commit is contained in:
zombieJ 2019-01-25 10:31:09 +08:00 committed by GitHub
parent 8bb3b10c01
commit d1fde3670c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 237 additions and 1248 deletions

View File

@ -12446,31 +12446,6 @@ Array [
placeholder="Select time"
value=""
/>
<a
class="config-time-picker-panel-clear-btn"
role="button"
tabindex="0"
title="clear"
>
<i
aria-label="icon: close-circle"
class="anticon anticon-close-circle config-time-picker-panel-clear-btn-icon"
>
<svg
aria-hidden="true"
class=""
data-icon="close-circle"
fill="currentColor"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</i>
</a>
</div>
<div
class="config-time-picker-panel-combobox"
@ -13417,31 +13392,6 @@ Array [
placeholder="Select time"
value=""
/>
<a
class="ant-time-picker-panel-clear-btn"
role="button"
tabindex="0"
title="clear"
>
<i
aria-label="icon: close-circle"
class="anticon anticon-close-circle ant-time-picker-panel-clear-btn-icon"
>
<svg
aria-hidden="true"
class=""
data-icon="close-circle"
fill="currentColor"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</i>
</a>
</div>
<div
class="ant-time-picker-panel-combobox"
@ -14388,31 +14338,6 @@ Array [
placeholder="Select time"
value=""
/>
<a
class="prefix-TimePicker-panel-clear-btn"
role="button"
tabindex="0"
title="clear"
>
<i
aria-label="icon: close-circle"
class="anticon anticon-close-circle prefix-TimePicker-panel-clear-btn-icon"
>
<svg
aria-hidden="true"
class=""
data-icon="close-circle"
fill="currentColor"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</i>
</a>
</div>
<div
class="prefix-TimePicker-panel-combobox"

View File

@ -228,6 +228,25 @@ exports[`renders ./components/time-picker/demo/disabled.md correctly 1`] = `
</svg>
</i>
</span>
<i
aria-label="icon: close-circle"
class="anticon anticon-close-circle ant-time-picker-clear"
tabindex="-1"
>
<svg
aria-hidden="true"
class=""
data-icon="close-circle"
fill="currentColor"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</i>
</span>
`;
@ -267,6 +286,25 @@ exports[`renders ./components/time-picker/demo/hide-column.md correctly 1`] = `
</svg>
</i>
</span>
<i
aria-label="icon: close-circle"
class="anticon anticon-close-circle ant-time-picker-clear"
tabindex="-1"
>
<svg
aria-hidden="true"
class=""
data-icon="close-circle"
fill="currentColor"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</i>
</span>
`;
@ -346,6 +384,25 @@ exports[`renders ./components/time-picker/demo/size.md correctly 1`] = `
</svg>
</i>
</span>
<i
aria-label="icon: close-circle"
class="anticon anticon-close-circle ant-time-picker-clear"
tabindex="-1"
>
<svg
aria-hidden="true"
class=""
data-icon="close-circle"
fill="currentColor"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</i>
</span>
<span
class="ant-time-picker "
@ -382,6 +439,25 @@ exports[`renders ./components/time-picker/demo/size.md correctly 1`] = `
</svg>
</i>
</span>
<i
aria-label="icon: close-circle"
class="anticon anticon-close-circle ant-time-picker-clear"
tabindex="-1"
>
<svg
aria-hidden="true"
class=""
data-icon="close-circle"
fill="currentColor"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</i>
</span>
<span
class="ant-time-picker ant-time-picker-small"
@ -418,6 +494,25 @@ exports[`renders ./components/time-picker/demo/size.md correctly 1`] = `
</svg>
</i>
</span>
<i
aria-label="icon: close-circle"
class="anticon anticon-close-circle ant-time-picker-clear"
tabindex="-1"
>
<svg
aria-hidden="true"
class=""
data-icon="close-circle"
fill="currentColor"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 0 1-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</i>
</span>
</div>
`;

View File

@ -1,5 +1,44 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TimePicker not render clean icon when allowClear is false 1`] = `
<span
class="ant-time-picker "
>
<input
class="ant-time-picker-input"
id=""
placeholder="Select time"
type="text"
value="00:00:00"
/>
<span
class="ant-time-picker-icon"
>
<i
aria-label="icon: clock-circle"
class="anticon anticon-clock-circle ant-time-picker-clock-icon"
>
<svg
aria-hidden="true"
class=""
data-icon="clock-circle"
fill="currentColor"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"
/>
</svg>
</i>
</span>
</span>
`;
exports[`TimePicker renders addon correctly 1`] = `
<div
class="ant-time-picker-panel-addon"

View File

@ -1,10 +1,21 @@
import React from 'react';
import { mount, render } from 'enzyme';
import RcTimePicker from 'rc-time-picker/lib/TimePicker';
import moment from 'moment';
import TimePicker from '..';
import focusTest from '../../../tests/shared/focusTest';
describe('TimePicker', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
afterEach(() => {
errorSpy.mockReset();
});
afterAll(() => {
errorSpy.mockRestore();
});
focusTest(TimePicker);
it('renders addon correctly', () => {
@ -15,4 +26,18 @@ describe('TimePicker', () => {
expect(addonWrapper).toMatchSnapshot();
});
it('allowEmpty deprecated', () => {
mount(<TimePicker allowEmpty />);
expect(errorSpy).toBeCalledWith(
'Warning: `allowEmpty` in TimePicker is deprecated. Please use `allowClear` instead.',
);
});
it('not render clean icon when allowClear is false', () => {
const wrapper = mount(
<TimePicker defaultValue={moment('2000-01-01 00:00:00')} allowClear={false} />,
);
expect(wrapper.render()).toMatchSnapshot();
});
});

View File

@ -24,7 +24,7 @@ import moment from 'moment';
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| addon | called from timepicker panel to render some addon to its bottom | function | - |
| allowEmpty | allow clearing text | boolean | true |
| allowClear | allow clearing text | boolean | true |
| autoFocus | get focus when component mounted | boolean | false |
| className | className of picker | string | '' |
| clearText | clear tooltip of icon | string | clear |

View File

@ -1,8 +1,10 @@
import * as React from 'react';
import * as moment from 'moment';
import omit from 'omit.js';
import { polyfill } from 'react-lifecycles-compat';
import RcTimePicker from 'rc-time-picker/lib/TimePicker';
import classNames from 'classnames';
import warning from '../_util/warning';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import defaultLocale from './locale/en_US';
@ -44,6 +46,7 @@ export interface TimePickerProps {
minuteStep?: number;
secondStep?: number;
allowEmpty?: boolean;
allowClear?: boolean;
inputReadOnly?: boolean;
clearText?: string;
defaultOpenValue?: moment.Moment;
@ -92,6 +95,11 @@ class TimePicker extends React.Component<TimePickerProps, any> {
this.state = {
value,
};
warning(
!('allowEmpty' in props),
'`allowEmpty` in TimePicker is deprecated. Please use `allowClear` instead.',
);
}
handleChange = (value: moment.Moment) => {
@ -133,65 +141,77 @@ class TimePicker extends React.Component<TimePickerProps, any> {
return 'HH:mm:ss';
}
getAllowClear() {
const { allowClear, allowEmpty } = this.props;
if ('allowClear' in this.props) {
return allowClear;
}
return allowEmpty;
}
renderInputIcon(prefixCls: string) {
const { suffixIcon } = this.props;
const clockIcon = (suffixIcon &&
(React.isValidElement<{ className?: string }>(suffixIcon) ? (
React.cloneElement(suffixIcon, {
className: classNames(suffixIcon.props.className, `${prefixCls}-clock-icon`),
})
) : (
<span className={`${prefixCls}-clock-icon`}>{suffixIcon}</span>
))) || <Icon type="clock-circle" className={`${prefixCls}-clock-icon`} />;
return <span className={`${prefixCls}-icon`}>{clockIcon}</span>;
}
renderClearIcon(prefixCls: string) {
const {} = this.props;
const clearIcon = <Icon type="close-circle" className={`${prefixCls}-clear`} theme="filled" />;
return clearIcon;
}
renderTimePicker = (locale: TimePickerLocale) => (
<ConfigConsumer>
{({ getPopupContainer: getContextPopupContainer, getPrefixCls }: ConfigConsumerProps) => {
const { getPopupContainer, prefixCls: customizePrefixCls, ...props } = this.props;
delete props.defaultValue;
const {
getPopupContainer,
prefixCls: customizePrefixCls,
className,
addon,
placeholder,
...props
} = this.props;
const { size } = props;
const pickerProps = omit(props, ['defaultValue', 'suffixIcon', 'allowEmpty', 'allowClear']);
const format = this.getDefaultFormat();
const prefixCls = getPrefixCls('time-picker', customizePrefixCls);
const className = classNames(props.className, {
[`${prefixCls}-${props.size}`]: !!props.size,
const pickerClassName = classNames(className, {
[`${prefixCls}-${size}`]: !!size,
});
const addon = (panel: React.ReactElement<any>) =>
props.addon ? (
<div className={`${prefixCls}-panel-addon`}>{props.addon(panel)}</div>
) : null;
const { suffixIcon } = props;
const clockIcon = (suffixIcon &&
(React.isValidElement<{ className?: string }>(suffixIcon) ? (
React.cloneElement(suffixIcon, {
className: classNames({
[suffixIcon.props.className!]: suffixIcon.props.className,
[`${prefixCls}-clock-icon`]: true,
}),
})
) : (
<span className={`${prefixCls}-clock-icon`}>{suffixIcon}</span>
))) || (
<Icon type="clock-circle" className={`${prefixCls}-clock-icon`} theme="outlined" />
);
const inputIcon = <span className={`${prefixCls}-icon`}>{clockIcon}</span>;
const clearIcon = (
<Icon
type="close-circle"
className={`${prefixCls}-panel-clear-btn-icon`}
theme="filled"
/>
);
const pickerAddon = (panel: React.ReactElement<any>) =>
addon ? <div className={`${prefixCls}-panel-addon`}>{addon(panel)}</div> : null;
return (
<RcTimePicker
{...generateShowHourMinuteSecond(format)}
{...props}
{...pickerProps}
allowEmpty={this.getAllowClear()}
prefixCls={prefixCls}
getPopupContainer={getPopupContainer || getContextPopupContainer}
ref={this.saveTimePicker}
format={format}
className={className}
className={pickerClassName}
value={this.state.value}
placeholder={props.placeholder === undefined ? locale.placeholder : props.placeholder}
placeholder={placeholder === undefined ? locale.placeholder : placeholder}
onChange={this.handleChange}
onOpen={this.handleOpenClose}
onClose={this.handleOpenClose}
addon={addon}
inputIcon={inputIcon}
clearIcon={clearIcon}
addon={pickerAddon}
inputIcon={this.renderInputIcon(prefixCls)}
clearIcon={this.renderClearIcon(prefixCls)}
/>
);
}}

View File

@ -25,7 +25,7 @@ import moment from 'moment';
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| addon | 选择框底部显示自定义的内容 | function | 无 |
| allowEmpty | 是否展示清除按钮 | boolean | true |
| allowClear | 是否展示清除按钮 | boolean | true |
| autoFocus | 自动获取焦点 | boolean | false |
| className | 选择器类名 | string | '' |
| clearText | 清除按钮的提示文案 | string | clear |

View File

@ -48,36 +48,6 @@
}
}
&-clear-btn {
position: absolute;
right: 8px;
cursor: pointer;
overflow: hidden;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
top: 7px;
margin: 0;
&-icon svg {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
font-size: @font-size-base;
color: @disabled-color;
display: inline-block;
transition: color 0.3s ease;
&:hover {
color: @text-color-secondary;
}
}
}
&-narrow &-input-wrap {
max-width: @time-picker-panel-column-width * 2;
}
@ -205,7 +175,8 @@
opacity: 0;
}
&-icon {
&-icon,
&-clear {
position: absolute;
z-index: 1;
user-select: none;
@ -224,6 +195,20 @@
}
}
&-clear {
opacity: 0;
z-index: 2;
background: @input-bg;
pointer-events: none;
&:hover {
color: @text-color-secondary;
}
}
&:hover &-clear {
opacity: 1;
pointer-events: auto;
}
&-large &-input {
.input-lg;
}

View File

@ -76,7 +76,7 @@
"rc-switch": "~1.8.0",
"rc-table": "~6.4.0",
"rc-tabs": "~9.6.0",
"rc-time-picker": "~3.5.0",
"rc-time-picker": "~3.6.1",
"rc-tooltip": "~3.7.3",
"rc-tree": "~1.14.6",
"rc-tree-select": "~2.5.0",