ant-design/components/time-picker/index.tsx

245 lines
7.0 KiB
TypeScript
Raw Normal View History

import * as React from 'react';
import * as moment from 'moment';
import omit from 'omit.js';
import RcTimePicker from 'rc-time-picker/lib/TimePicker';
2015-12-08 14:55:28 +08:00
import classNames from 'classnames';
import { ClockCircleOutlined, CloseCircleFilled } from '@ant-design/icons';
use ant design icons 4.0 (#18217) * feat: use @ant-design/icons@4.0 * feat: use createFromIconfontCN to make site works * feat: update doc for Icon * feat: use icon in component Alert * feat: use icon in component Avatar * feat: use icon in component Breadcrumb * feat: use icon in component Button * feat: use icon in component Cascader * feat: use icon in component Collapse * feat: use icon in component Datepicker * feat: use icon in component Dropdown * feat: use icon in component Form * feat: use icon in component Input * feat: use icon in component InputNumber * feat: use icon in component Layout * feat: use icon in component Mention * feat: use icon in component Message * feat: use icon in component Modal * feat: use icon in component Notification * feat: use icon in component PageHeader * feat: use icon in component Pagination * feat: use icon in component Popconfirm * feat: use icon in component Progress * feat: use icon in component Rate * feat: use icon in component Result * feat: use icon in component Select * feat: use icon in component Step * feat: use icon in component Switch * feat: use icon in component Table * feat: use icon in component Tab * feat: use icon in component Tag * feat: handle rest component which using Icon * fix: remove unused vars * feat: use latest alpha ant design icons * fix: failed test in uploadlist.test.js * test: update snapshot for icons * doc: add Icon for site * doc: use @ant-design/icons in site * chore: use latest icons * fix: tslint issue * fix: test cases * fix: types for react * fix: lint rules for import orders * fix: use @ant-design/icons@4.0.0-alpha.5 to avoid insert css in server render * fix: eslint error in demo/**.md * inject antd icons * update snapshot * fix site * doc: update docs * fix: code snippets icon in site * feat: use latest @ant-design/icons * fix: icon props in message
2019-08-13 14:07:17 +08:00
import warning from '../_util/warning';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import enUS from './locale/en_US';
2018-03-13 22:53:02 +08:00
import interopDefault from '../_util/interopDefault';
2016-07-09 10:52:58 +08:00
export function generateShowHourMinuteSecond(format: string) {
// Ref: http://momentjs.com/docs/#/parsing/string-format/
return {
2018-12-07 20:02:01 +08:00
showHour: format.indexOf('H') > -1 || format.indexOf('h') > -1 || format.indexOf('k') > -1,
showMinute: format.indexOf('m') > -1,
showSecond: format.indexOf('s') > -1,
};
}
2016-07-09 10:52:58 +08:00
export interface TimePickerProps {
className?: string;
size?: 'large' | 'default' | 'small';
value?: moment.Moment;
2018-01-09 22:35:53 +08:00
defaultValue?: moment.Moment | moment.Moment[];
open?: boolean;
2016-07-13 11:14:24 +08:00
format?: string;
onChange?: (time: moment.Moment, timeString: string) => void;
2017-04-28 09:48:48 +08:00
onOpenChange?: (open: boolean) => void;
onAmPmChange?: (ampm: 'AM' | 'PM') => void;
2016-07-13 11:14:24 +08:00
disabled?: boolean;
placeholder?: string;
prefixCls?: string;
2016-07-13 11:14:24 +08:00
hideDisabledOptions?: boolean;
disabledHours?: () => number[];
disabledMinutes?: (selectedHour: number) => number[];
disabledSeconds?: (selectedHour: number, selectedMinute: number) => number[];
2016-07-13 11:14:24 +08:00
style?: React.CSSProperties;
2019-04-28 11:47:22 +08:00
getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;
2016-11-06 14:53:29 +08:00
addon?: Function;
use12Hours?: boolean;
focusOnOpen?: boolean;
hourStep?: number;
minuteStep?: number;
secondStep?: number;
allowEmpty?: boolean;
allowClear?: boolean;
inputReadOnly?: boolean;
clearText?: string;
defaultOpenValue?: moment.Moment;
popupClassName?: string;
popupStyle?: React.CSSProperties;
2018-09-16 19:45:27 +08:00
suffixIcon?: React.ReactNode;
clearIcon?: React.ReactNode;
locale?: TimePickerLocale;
2016-07-09 10:52:58 +08:00
}
2016-08-22 17:26:14 +08:00
2017-11-20 18:27:36 +08:00
export interface TimePickerLocale {
placeholder: string;
}
2018-08-08 14:47:13 +08:00
class TimePicker extends React.Component<TimePickerProps, any> {
static defaultProps = {
align: {
offset: [0, -2],
},
disabledHours: undefined,
disabledMinutes: undefined,
disabledSeconds: undefined,
hideDisabledOptions: false,
placement: 'bottomLeft',
transitionName: 'slide-up',
focusOnOpen: true,
2016-07-13 11:14:24 +08:00
};
2015-11-16 23:11:41 +08:00
2018-08-08 14:47:13 +08:00
static getDerivedStateFromProps(nextProps: TimePickerProps) {
if ('value' in nextProps) {
return { value: nextProps.value };
}
return null;
}
2017-11-20 18:27:36 +08:00
private timePickerRef: typeof RcTimePicker;
2016-08-22 17:26:14 +08:00
constructor(props: TimePickerProps) {
super(props);
const value = props.value || props.defaultValue;
2018-03-13 22:53:02 +08:00
if (value && !interopDefault(moment).isMoment(value)) {
throw new Error(
'The value/defaultValue of TimePicker must be a moment object after `antd@2.0`, ' +
2018-12-07 20:02:01 +08:00
'see: https://u.ant.design/time-picker-value',
);
}
this.state = {
value,
};
warning(
!('allowEmpty' in props),
'TimePicker',
'`allowEmpty` is deprecated. Please use `allowClear` instead.',
);
}
2015-11-16 23:11:41 +08:00
2019-08-05 18:38:10 +08:00
getDefaultFormat() {
const { format, use12Hours } = this.props;
if (format) {
return format;
}
2019-08-05 18:38:10 +08:00
if (use12Hours) {
return 'h:mm:ss a';
}
return 'HH:mm:ss';
}
getAllowClear() {
const { allowClear, allowEmpty } = this.props;
if ('allowClear' in this.props) {
return allowClear;
2016-10-24 16:30:38 +08:00
}
2019-08-05 18:38:10 +08:00
return allowEmpty;
}
getDefaultLocale = () => {
const defaultLocale = {
...enUS,
...this.props.locale,
};
return defaultLocale;
2018-12-07 20:02:01 +08:00
};
2015-11-19 15:53:40 +08:00
2017-11-20 18:27:36 +08:00
handleOpenClose = ({ open }: { open: boolean }) => {
const { onOpenChange } = this.props;
if (onOpenChange) {
onOpenChange(open);
}
2018-12-07 20:02:01 +08:00
};
2017-11-20 18:27:36 +08:00
saveTimePicker = (timePickerRef: typeof RcTimePicker) => {
this.timePickerRef = timePickerRef;
2018-12-07 20:02:01 +08:00
};
2019-08-05 18:38:10 +08:00
handleChange = (value: moment.Moment) => {
if (!('value' in this.props)) {
this.setState({ value });
}
const { onChange, format = 'HH:mm:ss' } = this.props;
if (onChange) {
onChange(value, (value && value.format(format)) || '');
}
};
focus() {
this.timePickerRef.focus();
}
blur() {
this.timePickerRef.blur();
}
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`),
})) || <ClockCircleOutlined className={`${prefixCls}-clock-icon`} />;
return <span className={`${prefixCls}-icon`}>{clockIcon}</span>;
}
renderClearIcon(prefixCls: string) {
const { clearIcon } = this.props;
const clearIconPrefixCls = `${prefixCls}-clear`;
if (clearIcon && React.isValidElement<{ className?: string }>(clearIcon)) {
return React.cloneElement(clearIcon, {
className: classNames(clearIcon.props.className, clearIconPrefixCls),
});
}
use ant design icons 4.0 (#18217) * feat: use @ant-design/icons@4.0 * feat: use createFromIconfontCN to make site works * feat: update doc for Icon * feat: use icon in component Alert * feat: use icon in component Avatar * feat: use icon in component Breadcrumb * feat: use icon in component Button * feat: use icon in component Cascader * feat: use icon in component Collapse * feat: use icon in component Datepicker * feat: use icon in component Dropdown * feat: use icon in component Form * feat: use icon in component Input * feat: use icon in component InputNumber * feat: use icon in component Layout * feat: use icon in component Mention * feat: use icon in component Message * feat: use icon in component Modal * feat: use icon in component Notification * feat: use icon in component PageHeader * feat: use icon in component Pagination * feat: use icon in component Popconfirm * feat: use icon in component Progress * feat: use icon in component Rate * feat: use icon in component Result * feat: use icon in component Select * feat: use icon in component Step * feat: use icon in component Switch * feat: use icon in component Table * feat: use icon in component Tab * feat: use icon in component Tag * feat: handle rest component which using Icon * fix: remove unused vars * feat: use latest alpha ant design icons * fix: failed test in uploadlist.test.js * test: update snapshot for icons * doc: add Icon for site * doc: use @ant-design/icons in site * chore: use latest icons * fix: tslint issue * fix: test cases * fix: types for react * fix: lint rules for import orders * fix: use @ant-design/icons@4.0.0-alpha.5 to avoid insert css in server render * fix: eslint error in demo/**.md * inject antd icons * update snapshot * fix site * doc: update docs * fix: code snippets icon in site * feat: use latest @ant-design/icons * fix: icon props in message
2019-08-13 14:07:17 +08:00
return <CloseCircleFilled className={clearIconPrefixCls} />;
}
renderTimePicker = (locale: TimePickerLocale) => (
<ConfigConsumer>
{({ getPopupContainer: getContextPopupContainer, getPrefixCls }: ConfigConsumerProps) => {
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 pickerClassName = classNames(className, {
[`${prefixCls}-${size}`]: !!size,
});
const pickerAddon = (panel: React.ReactElement<any>) =>
addon ? <div className={`${prefixCls}-panel-addon`}>{addon(panel)}</div> : null;
return (
<RcTimePicker
{...generateShowHourMinuteSecond(format)}
{...pickerProps}
allowEmpty={this.getAllowClear()}
prefixCls={prefixCls}
getPopupContainer={getPopupContainer || getContextPopupContainer}
ref={this.saveTimePicker}
format={format}
className={pickerClassName}
value={this.state.value}
placeholder={placeholder === undefined ? locale.placeholder : placeholder}
onChange={this.handleChange}
onOpen={this.handleOpenClose}
onClose={this.handleOpenClose}
addon={pickerAddon}
inputIcon={this.renderInputIcon(prefixCls)}
clearIcon={this.renderClearIcon(prefixCls)}
/>
);
}}
</ConfigConsumer>
);
render() {
return (
<LocaleReceiver componentName="TimePicker" defaultLocale={this.getDefaultLocale()}>
{this.renderTimePicker}
</LocaleReceiver>
);
}
}
2018-08-08 14:47:13 +08:00
export default TimePicker;