mirror of
https://gitee.com/ant-design-vue/ant-design-vue.git
synced 2024-11-30 02:57:50 +08:00
add time picker
This commit is contained in:
parent
816fe56d5f
commit
615c72091e
58
components/time-picker/index.en-US.md
Normal file
58
components/time-picker/index.en-US.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
category: Components
|
||||||
|
type: Data Entry
|
||||||
|
title: TimePicker
|
||||||
|
---
|
||||||
|
|
||||||
|
To select/input a time.
|
||||||
|
|
||||||
|
## When To Use
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
By clicking the input box, you can select a time from a popup panel.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import moment from 'moment';
|
||||||
|
<TimePicker defaultValue={moment('13:30:56', 'HH:mm:ss')} />
|
||||||
|
```
|
||||||
|
|
||||||
|
| Property | Description | Type | Default |
|
||||||
|
| -------- | ----------- | ---- | ------- |
|
||||||
|
| addon | called from timepicker panel to render some addon to its bottom | function | - |
|
||||||
|
| allowEmpty | 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 |
|
||||||
|
| defaultOpenValue | default open panel value, used to set utcOffset,locale if value/defaultValue absent | [moment](http://momentjs.com/) | moment() |
|
||||||
|
| defaultValue | to set default time | [moment](http://momentjs.com/) | - |
|
||||||
|
| disabled | determine whether the TimePicker is disabled | boolean | false |
|
||||||
|
| disabledHours | to specify the hours that cannot be selected | function() | - |
|
||||||
|
| disabledMinutes | to specify the minutes that cannot be selected | function(selectedHour) | - |
|
||||||
|
| disabledSeconds | to specify the seconds that cannot be selected | function(selectedHour, selectedMinute) | - |
|
||||||
|
| format | to set the time format | string | "HH:mm:ss" |
|
||||||
|
| getPopupContainer | to set the container of the floating layer, while the default is to create a div element in body | function(trigger) | - |
|
||||||
|
| hideDisabledOptions | hide the options that can not be selected | boolean | false |
|
||||||
|
| hourStep | interval between hours in picker | number | 1 |
|
||||||
|
| minuteStep | interval between minutes in picker | number | 1 |
|
||||||
|
| open | whether to popup panel | boolean | false |
|
||||||
|
| placeholder | display when there's no value | string | "Select a time" |
|
||||||
|
| popupClassName | className of panel | string | '' |
|
||||||
|
| secondStep | interval between seconds in picker | number | 1 |
|
||||||
|
| use12Hours | display as 12 hours format, with default format `h:mm:ss a` | boolean | false |
|
||||||
|
| value | to set time | [moment](http://momentjs.com/) | - |
|
||||||
|
| onChange | a callback function, can be executed when the selected time is changing | function(time: moment, timeString: string): void | - |
|
||||||
|
| onOpenChange | a callback function which will be called while panel opening/closing | (open: boolean): void | - |
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| ---- | ----------- |
|
||||||
|
| blur() | remove focus |
|
||||||
|
| focus() | get focus |
|
||||||
|
|
||||||
|
<style>.code-box-demo .ant-time-picker { margin: 0 8px 12px 0; }</style>
|
179
components/time-picker/index.vue
Normal file
179
components/time-picker/index.vue
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
<script>
|
||||||
|
import * as moment from 'moment';
|
||||||
|
import RcTimePicker from 'rc-time-picker/lib/TimePicker';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||||
|
import defaultLocale from './locale/en_US';
|
||||||
|
|
||||||
|
export function generateShowHourMinuteSecond(format: string) {
|
||||||
|
// Ref: http://momentjs.com/docs/#/parsing/string-format/
|
||||||
|
return {
|
||||||
|
showHour: (
|
||||||
|
format.indexOf('H') > -1 ||
|
||||||
|
format.indexOf('h') > -1 ||
|
||||||
|
format.indexOf('k') > -1
|
||||||
|
),
|
||||||
|
showMinute: format.indexOf('m') > -1,
|
||||||
|
showSecond: format.indexOf('s') > -1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimePickerProps {
|
||||||
|
className?: string;
|
||||||
|
size?: 'large' | 'default' | 'small';
|
||||||
|
value?: moment.Moment;
|
||||||
|
defaultValue?: moment.Moment | moment.Moment[];
|
||||||
|
open?: boolean;
|
||||||
|
format?: string;
|
||||||
|
onChange?: (time: moment.Moment, timeString: string) => void;
|
||||||
|
onOpenChange?: (open: boolean) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
placeholder?: string;
|
||||||
|
prefixCls?: string;
|
||||||
|
hideDisabledOptions?: boolean;
|
||||||
|
disabledHours?: () => number[];
|
||||||
|
disabledMinutes?: (selectedHour: number) => number[];
|
||||||
|
disabledSeconds?: (selectedHour: number, selectedMinute: number) => number[];
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
getPopupContainer?: (triggerNode: Element) => HTMLElement;
|
||||||
|
addon?: Function;
|
||||||
|
use12Hours?: boolean;
|
||||||
|
focusOnOpen?: boolean;
|
||||||
|
hourStep?: number;
|
||||||
|
minuteStep?: number;
|
||||||
|
secondStep?: number;
|
||||||
|
allowEmpty?: boolean;
|
||||||
|
clearText?: string;
|
||||||
|
defaultOpenValue?: moment.Moment;
|
||||||
|
popupClassName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimePickerLocale {
|
||||||
|
placeholder: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class TimePicker extends React.Component<TimePickerProps, any> {
|
||||||
|
static defaultProps = {
|
||||||
|
prefixCls: 'ant-time-picker',
|
||||||
|
align: {
|
||||||
|
offset: [0, -2],
|
||||||
|
},
|
||||||
|
disabled: false,
|
||||||
|
disabledHours: undefined,
|
||||||
|
disabledMinutes: undefined,
|
||||||
|
disabledSeconds: undefined,
|
||||||
|
hideDisabledOptions: false,
|
||||||
|
placement: 'bottomLeft',
|
||||||
|
transitionName: 'slide-up',
|
||||||
|
focusOnOpen: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
private timePickerRef: typeof RcTimePicker;
|
||||||
|
|
||||||
|
constructor(props: TimePickerProps) {
|
||||||
|
super(props);
|
||||||
|
const value = props.value || props.defaultValue;
|
||||||
|
if (value && !moment.isMoment(value)) {
|
||||||
|
throw new Error(
|
||||||
|
'The value/defaultValue of TimePicker must be a moment object after `antd@2.0`, ' +
|
||||||
|
'see: https://u.ant.design/time-picker-value',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.state = {
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps: TimePickerProps) {
|
||||||
|
if ('value' in nextProps) {
|
||||||
|
this.setState({ value: nextProps.value });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) || '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOpenClose = ({ open }: { open: boolean }) => {
|
||||||
|
const { onOpenChange } = this.props;
|
||||||
|
if (onOpenChange) {
|
||||||
|
onOpenChange(open);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveTimePicker = (timePickerRef: typeof RcTimePicker) => {
|
||||||
|
this.timePickerRef = timePickerRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
this.timePickerRef.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
blur() {
|
||||||
|
this.timePickerRef.blur();
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultFormat() {
|
||||||
|
const { format, use12Hours } = this.props;
|
||||||
|
if (format) {
|
||||||
|
return format;
|
||||||
|
} else if (use12Hours) {
|
||||||
|
return 'h:mm:ss a';
|
||||||
|
}
|
||||||
|
return 'HH:mm:ss';
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTimePicker = (locale: TimePickerLocale) => {
|
||||||
|
const props = {
|
||||||
|
...this.props,
|
||||||
|
};
|
||||||
|
delete props.defaultValue;
|
||||||
|
|
||||||
|
const format = this.getDefaultFormat();
|
||||||
|
const className = classNames(props.className, {
|
||||||
|
[`${props.prefixCls}-${props.size}`]: !!props.size,
|
||||||
|
});
|
||||||
|
|
||||||
|
const addon = (panel: React.ReactElement<any>) => (
|
||||||
|
props.addon ? (
|
||||||
|
<div className={`${props.prefixCls}-panel-addon`}>
|
||||||
|
{props.addon(panel)}
|
||||||
|
</div>
|
||||||
|
) : null
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RcTimePicker
|
||||||
|
{...generateShowHourMinuteSecond(format)}
|
||||||
|
{...props}
|
||||||
|
ref={this.saveTimePicker}
|
||||||
|
format={format}
|
||||||
|
className={className}
|
||||||
|
value={this.state.value}
|
||||||
|
placeholder={props.placeholder === undefined ? locale.placeholder : props.placeholder}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
onOpen={this.handleOpenClose}
|
||||||
|
onClose={this.handleOpenClose}
|
||||||
|
addon={addon}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<LocaleReceiver
|
||||||
|
componentName="TimePicker"
|
||||||
|
defaultLocale={defaultLocale}
|
||||||
|
>
|
||||||
|
{this.renderTimePicker}
|
||||||
|
</LocaleReceiver>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
59
components/time-picker/index.zh-CN.md
Normal file
59
components/time-picker/index.zh-CN.md
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
---
|
||||||
|
category: Components
|
||||||
|
subtitle: 时间选择框
|
||||||
|
type: Data Entry
|
||||||
|
title: TimePicker
|
||||||
|
---
|
||||||
|
|
||||||
|
输入或选择时间的控件。
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
当用户需要输入一个时间,可以点击标准输入框,弹出时间面板进行选择。
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import moment from 'moment';
|
||||||
|
<TimePicker defaultValue={moment('13:30:56', 'HH:mm:ss')} />
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| addon | 选择框底部显示自定义的内容 | function | 无 |
|
||||||
|
| allowEmpty | 是否展示清除按钮 | boolean | true |
|
||||||
|
| autoFocus | 自动获取焦点 | boolean | false |
|
||||||
|
| className | 选择器类名 | string | '' |
|
||||||
|
| clearText | 清除按钮的提示文案 | string | clear |
|
||||||
|
| defaultOpenValue | 当 defaultValue/value 不存在时,可以设置面板打开时默认选中的值 | [moment](http://momentjs.com/) | moment() |
|
||||||
|
| defaultValue | 默认时间 | [moment](http://momentjs.com/) | 无 |
|
||||||
|
| disabled | 禁用全部操作 | boolean | false |
|
||||||
|
| disabledHours | 禁止选择部分小时选项 | function() | 无 |
|
||||||
|
| disabledMinutes | 禁止选择部分分钟选项 | function(selectedHour) | 无 |
|
||||||
|
| disabledSeconds | 禁止选择部分秒选项 | function(selectedHour, selectedMinute) | 无 |
|
||||||
|
| format | 展示的时间格式 | string | "HH:mm:ss" |
|
||||||
|
| getPopupContainer | 定义浮层的容器,默认为 body 上新建 div | function(trigger) | 无 |
|
||||||
|
| hideDisabledOptions | 隐藏禁止选择的选项 | boolean | false |
|
||||||
|
| hourStep | 小时选项间隔 | number | 1 |
|
||||||
|
| minuteStep | 分钟选项间隔 | number | 1 |
|
||||||
|
| open | 面板是否打开 | boolean | false |
|
||||||
|
| placeholder | 没有值的时候显示的内容 | string | "请选择时间" |
|
||||||
|
| popupClassName | 弹出层类名 | string | '' |
|
||||||
|
| secondStep | 秒选项间隔 | number | 1 |
|
||||||
|
| use12Hours | 使用 12 小时制,为 true 时 `format` 默认为 `h:mm:ss a` | boolean | false |
|
||||||
|
| value | 当前时间 | [moment](http://momentjs.com/) | 无 |
|
||||||
|
| onChange | 时间发生变化的回调 | function(time: moment, timeString: string): void | 无 |
|
||||||
|
| onOpenChange | 面板打开/关闭时的回调 | (open: boolean): void | 无 |
|
||||||
|
|
||||||
|
## 方法
|
||||||
|
|
||||||
|
| 名称 | 描述 |
|
||||||
|
| --- | --- |
|
||||||
|
| blur() | 移除焦点 |
|
||||||
|
| focus() | 获取焦点 |
|
||||||
|
|
||||||
|
<style>.code-box-demo .ant-time-picker { margin: 0 8px 12px 0; }</style>
|
5
components/time-picker/locale/ar_EG.tsx.js
Normal file
5
components/time-picker/locale/ar_EG.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'اختيار الوقت',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default locale
|
5
components/time-picker/locale/bg_BG.tsx.js
Normal file
5
components/time-picker/locale/bg_BG.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Избор на час',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/ca_ES.tsx.js
Normal file
5
components/time-picker/locale/ca_ES.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Seleccionar hora',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/cs_CZ.tsx.js
Normal file
5
components/time-picker/locale/cs_CZ.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Vybrat čas',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/de_DE.tsx.js
Normal file
5
components/time-picker/locale/de_DE.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Zeit auswählen',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/el_GR.tsx.js
Normal file
5
components/time-picker/locale/el_GR.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Επιλέξτε ώρα',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/en_GB.tsx.js
Normal file
5
components/time-picker/locale/en_GB.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Select time',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/en_US.tsx.js
Normal file
5
components/time-picker/locale/en_US.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Select time',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/es_ES.tsx.js
Normal file
5
components/time-picker/locale/es_ES.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Seleccionar hora',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/et_EE.tsx.js
Normal file
5
components/time-picker/locale/et_EE.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Vali aeg',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/fa_IR.tsx.js
Normal file
5
components/time-picker/locale/fa_IR.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'انتخاب زمان',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/fi_FI.tsx.js
Normal file
5
components/time-picker/locale/fi_FI.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Valitse aika',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/fr_BE.tsx.js
Normal file
5
components/time-picker/locale/fr_BE.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Sélectionner l\'heure',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/fr_FR.tsx.js
Normal file
5
components/time-picker/locale/fr_FR.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Sélectionner l\'heure',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/is_IS.tsx.js
Normal file
5
components/time-picker/locale/is_IS.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Velja tíma',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/it_IT.tsx.js
Normal file
5
components/time-picker/locale/it_IT.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Selezionare il tempo',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/ja_JP.tsx.js
Normal file
5
components/time-picker/locale/ja_JP.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: '時刻を選択',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/ko_KR.tsx.js
Normal file
5
components/time-picker/locale/ko_KR.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: '날짜 선택',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/ku_IQ.tsx.js
Executable file
5
components/time-picker/locale/ku_IQ.tsx.js
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Demê hilbijêre',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/nb_NO.tsx.js
Normal file
5
components/time-picker/locale/nb_NO.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Velg tid',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/nl_BE.tsx.js
Normal file
5
components/time-picker/locale/nl_BE.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Selecteer tijd',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/nl_NL.tsx.js
Normal file
5
components/time-picker/locale/nl_NL.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Selecteer tijd',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/pl_PL.tsx.js
Normal file
5
components/time-picker/locale/pl_PL.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Wybierz godzinę',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/pt_BR.tsx.js
Normal file
5
components/time-picker/locale/pt_BR.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Hora',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/pt_PT.tsx.js
Normal file
5
components/time-picker/locale/pt_PT.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Hora',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
8
components/time-picker/locale/ru_RU.tsx.js
Normal file
8
components/time-picker/locale/ru_RU.tsx.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* Created by Andrey Gayvoronsky on 13/04/16.
|
||||||
|
*/
|
||||||
|
const locale = {
|
||||||
|
placeholder: 'Выберите время',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/sk_SK.tsx.js
Normal file
5
components/time-picker/locale/sk_SK.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Vybrať čas',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/sr_RS.tsx.js
Normal file
5
components/time-picker/locale/sr_RS.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Izaberite vreme',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/sv_SE.tsx.js
Normal file
5
components/time-picker/locale/sv_SE.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Välj tid',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/th_TH.tsx.js
Normal file
5
components/time-picker/locale/th_TH.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'เลือกเวลา',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/tr_TR.tsx.js
Normal file
5
components/time-picker/locale/tr_TR.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Zaman Seç',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/uk_UA.tsx.js
Normal file
5
components/time-picker/locale/uk_UA.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Оберіть час',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/vi_VN.tsx.js
Normal file
5
components/time-picker/locale/vi_VN.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: 'Chọn thời gian',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/zh_CN.tsx.js
Normal file
5
components/time-picker/locale/zh_CN.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: '请选择时间',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
5
components/time-picker/locale/zh_TW.tsx.js
Normal file
5
components/time-picker/locale/zh_TW.tsx.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const locale = {
|
||||||
|
placeholder: '請選擇時間',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default locale;
|
234
components/time-picker/style/index.less
Normal file
234
components/time-picker/style/index.less
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
@import "../../style/themes/default";
|
||||||
|
@import "../../style/mixins/index";
|
||||||
|
@import "../../input/style/mixin";
|
||||||
|
|
||||||
|
@timepicker-prefix-cls: ~"@{ant-prefix}-time-picker";
|
||||||
|
@timepicker-item-height: 32px;
|
||||||
|
|
||||||
|
.@{timepicker-prefix-cls}-panel {
|
||||||
|
.reset-component;
|
||||||
|
z-index: @zindex-picker;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
&-inner {
|
||||||
|
position: relative;
|
||||||
|
outline: none;
|
||||||
|
list-style: none;
|
||||||
|
font-size: @font-size-base;
|
||||||
|
text-align: left;
|
||||||
|
background-color: @component-background;
|
||||||
|
border-radius: @border-radius-base;
|
||||||
|
box-shadow: @box-shadow-base;
|
||||||
|
background-clip: padding-box;
|
||||||
|
overflow: hidden;
|
||||||
|
left: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-input {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
width: 100%;
|
||||||
|
cursor: auto;
|
||||||
|
outline: 0;
|
||||||
|
|
||||||
|
.placeholder;
|
||||||
|
|
||||||
|
&-wrap {
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
padding: 7px 2px 7px @control-padding-horizontal;
|
||||||
|
border-bottom: @border-width-base @border-style-base @border-color-split;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-invalid {
|
||||||
|
border-color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-clear-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 20px;
|
||||||
|
top: 7px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-clear-btn:after {
|
||||||
|
font-size: @font-size-base - 2px;
|
||||||
|
color: @disabled-color;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 1;
|
||||||
|
width: 20px;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
.iconfont-font("\e62e");
|
||||||
|
}
|
||||||
|
|
||||||
|
&-clear-btn:hover:after {
|
||||||
|
color: @text-color-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-narrow &-input-wrap {
|
||||||
|
max-width: @time-picker-panel-column-width * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-select {
|
||||||
|
float: left;
|
||||||
|
font-size: @font-size-base;
|
||||||
|
border-left: @border-width-base @border-style-base @border-color-split;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: @time-picker-panel-column-width;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative; // Fix chrome weird render bug
|
||||||
|
max-height: @timepicker-item-height * 6;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
border-left: 0;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:only-child {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 0 @timepicker-item-height * 5;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
box-sizing: content-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 0 0 @control-padding-horizontal;
|
||||||
|
width: 100%;
|
||||||
|
height: @timepicker-item-height;
|
||||||
|
line-height: @timepicker-item-height;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:hover {
|
||||||
|
background: @item-hover-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
li&-option-selected {
|
||||||
|
background: @time-picker-selected-bg;
|
||||||
|
font-weight: bold;
|
||||||
|
&:hover {
|
||||||
|
background: @time-picker-selected-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li&-option-disabled {
|
||||||
|
color: @btn-disable-color;
|
||||||
|
&:hover {
|
||||||
|
background: transparent;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-combobox {
|
||||||
|
.clearfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-addon {
|
||||||
|
padding: 8px;
|
||||||
|
border-top: @border-width-base @border-style-base @border-color-split;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.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} {
|
||||||
|
.reset-component;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
outline: none;
|
||||||
|
transition: opacity .3s;
|
||||||
|
width: 128px;
|
||||||
|
|
||||||
|
&-input {
|
||||||
|
.input;
|
||||||
|
&[disabled] {
|
||||||
|
.disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-open {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
position: absolute;
|
||||||
|
user-select: none;
|
||||||
|
transition: all .3s @ease-in-out;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
line-height: 14px;
|
||||||
|
right: @control-padding-horizontal - 1px;
|
||||||
|
color: @disabled-color;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -7px;
|
||||||
|
&:after {
|
||||||
|
content: "\e641";
|
||||||
|
font-family: "anticon";
|
||||||
|
color: @disabled-color;
|
||||||
|
display: block;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-large &-input {
|
||||||
|
.input-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-small &-input {
|
||||||
|
.input-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-small &-icon {
|
||||||
|
right: @control-padding-horizontal-sm - 1px;
|
||||||
|
}
|
||||||
|
}
|
5
components/time-picker/style/index.tsx
Normal file
5
components/time-picker/style/index.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import '../../style/index.less';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
// style dependencies
|
||||||
|
import '../../input/style';
|
190
components/vc-time-picker/Combobox.vue
Normal file
190
components/vc-time-picker/Combobox.vue
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
<script>
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import Select from './Select'
|
||||||
|
|
||||||
|
const formatOption = (option, disabledOptions) => {
|
||||||
|
let value = `${option}`
|
||||||
|
if (option < 10) {
|
||||||
|
value = `0${option}`
|
||||||
|
}
|
||||||
|
|
||||||
|
let disabled = false
|
||||||
|
if (disabledOptions && disabledOptions.indexOf(option) >= 0) {
|
||||||
|
disabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
value,
|
||||||
|
disabled,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Combobox extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
format: PropTypes.string,
|
||||||
|
defaultOpenValue: PropTypes.object,
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
value: PropTypes.object,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
showHour: PropTypes.bool,
|
||||||
|
showMinute: PropTypes.bool,
|
||||||
|
showSecond: PropTypes.bool,
|
||||||
|
hourOptions: PropTypes.array,
|
||||||
|
minuteOptions: PropTypes.array,
|
||||||
|
secondOptions: PropTypes.array,
|
||||||
|
disabledHours: PropTypes.func,
|
||||||
|
disabledMinutes: PropTypes.func,
|
||||||
|
disabledSeconds: PropTypes.func,
|
||||||
|
onCurrentSelectPanelChange: PropTypes.func,
|
||||||
|
use12Hours: PropTypes.bool,
|
||||||
|
isAM: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
onItemChange = (type, itemValue) => {
|
||||||
|
const { onChange, defaultOpenValue, use12Hours } = this.props
|
||||||
|
const value = (this.props.value || defaultOpenValue).clone()
|
||||||
|
|
||||||
|
if (type === 'hour') {
|
||||||
|
if (use12Hours) {
|
||||||
|
if (this.props.isAM) {
|
||||||
|
value.hour(+itemValue % 12)
|
||||||
|
} else {
|
||||||
|
value.hour((+itemValue % 12) + 12)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value.hour(+itemValue)
|
||||||
|
}
|
||||||
|
} else if (type === 'minute') {
|
||||||
|
value.minute(+itemValue)
|
||||||
|
} else if (type === 'ampm') {
|
||||||
|
const ampm = itemValue.toUpperCase()
|
||||||
|
if (use12Hours) {
|
||||||
|
if (ampm === 'PM' && value.hour() < 12) {
|
||||||
|
value.hour((value.hour() % 12) + 12)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ampm === 'AM') {
|
||||||
|
if (value.hour() >= 12) {
|
||||||
|
value.hour(value.hour() - 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value.second(+itemValue)
|
||||||
|
}
|
||||||
|
onChange(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
onEnterSelectPanel = (range) => {
|
||||||
|
this.props.onCurrentSelectPanelChange(range)
|
||||||
|
}
|
||||||
|
|
||||||
|
getHourSelect (hour) {
|
||||||
|
const { prefixCls, hourOptions, disabledHours, showHour, use12Hours } = this.props
|
||||||
|
if (!showHour) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const disabledOptions = disabledHours()
|
||||||
|
let hourOptionsAdj
|
||||||
|
let hourAdj
|
||||||
|
if (use12Hours) {
|
||||||
|
hourOptionsAdj = [12].concat(hourOptions.filter(h => h < 12 && h > 0))
|
||||||
|
hourAdj = (hour % 12) || 12
|
||||||
|
} else {
|
||||||
|
hourOptionsAdj = hourOptions
|
||||||
|
hourAdj = hour
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
options={hourOptionsAdj.map(option => formatOption(option, disabledOptions))}
|
||||||
|
selectedIndex={hourOptionsAdj.indexOf(hourAdj)}
|
||||||
|
type='hour'
|
||||||
|
onSelect={this.onItemChange}
|
||||||
|
onMouseEnter={this.onEnterSelectPanel.bind(this, 'hour')}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getMinuteSelect (minute) {
|
||||||
|
const { prefixCls, minuteOptions, disabledMinutes, defaultOpenValue, showMinute } = this.props
|
||||||
|
if (!showMinute) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const value = this.props.value || defaultOpenValue
|
||||||
|
const disabledOptions = disabledMinutes(value.hour())
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
options={minuteOptions.map(option => formatOption(option, disabledOptions))}
|
||||||
|
selectedIndex={minuteOptions.indexOf(minute)}
|
||||||
|
type='minute'
|
||||||
|
onSelect={this.onItemChange}
|
||||||
|
onMouseEnter={this.onEnterSelectPanel.bind(this, 'minute')}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getSecondSelect (second) {
|
||||||
|
const { prefixCls, secondOptions, disabledSeconds, showSecond, defaultOpenValue } = this.props
|
||||||
|
if (!showSecond) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const value = this.props.value || defaultOpenValue
|
||||||
|
const disabledOptions = disabledSeconds(value.hour(), value.minute())
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
options={secondOptions.map(option => formatOption(option, disabledOptions))}
|
||||||
|
selectedIndex={secondOptions.indexOf(second)}
|
||||||
|
type='second'
|
||||||
|
onSelect={this.onItemChange}
|
||||||
|
onMouseEnter={this.onEnterSelectPanel.bind(this, 'second')}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getAMPMSelect () {
|
||||||
|
const { prefixCls, use12Hours, format } = this.props
|
||||||
|
if (!use12Hours) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const AMPMOptions = ['am', 'pm'] // If format has A char, then we should uppercase AM/PM
|
||||||
|
.map(c => format.match(/\sA/) ? c.toUpperCase() : c)
|
||||||
|
.map(c => ({ value: c }))
|
||||||
|
|
||||||
|
const selected = this.props.isAM ? 0 : 1
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
options={AMPMOptions}
|
||||||
|
selectedIndex={selected}
|
||||||
|
type='ampm'
|
||||||
|
onSelect={this.onItemChange}
|
||||||
|
onMouseEnter={this.onEnterSelectPanel.bind(this, 'ampm')}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { prefixCls, defaultOpenValue } = this.props
|
||||||
|
const value = this.props.value || defaultOpenValue
|
||||||
|
return (
|
||||||
|
<div className={`${prefixCls}-combobox`}>
|
||||||
|
{this.getHourSelect(value.hour())}
|
||||||
|
{this.getMinuteSelect(value.minute())}
|
||||||
|
{this.getSecondSelect(value.second())}
|
||||||
|
{this.getAMPMSelect(value.hour())}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Combobox
|
||||||
|
|
||||||
|
</script>
|
202
components/vc-time-picker/Header.vue
Normal file
202
components/vc-time-picker/Header.vue
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
<script>
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
|
class Header extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
format: PropTypes.string,
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
disabledDate: PropTypes.func,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
clearText: PropTypes.string,
|
||||||
|
value: PropTypes.object,
|
||||||
|
inputReadOnly: PropTypes.bool,
|
||||||
|
hourOptions: PropTypes.array,
|
||||||
|
minuteOptions: PropTypes.array,
|
||||||
|
secondOptions: PropTypes.array,
|
||||||
|
disabledHours: PropTypes.func,
|
||||||
|
disabledMinutes: PropTypes.func,
|
||||||
|
disabledSeconds: PropTypes.func,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
onClear: PropTypes.func,
|
||||||
|
onEsc: PropTypes.func,
|
||||||
|
allowEmpty: PropTypes.bool,
|
||||||
|
defaultOpenValue: PropTypes.object,
|
||||||
|
currentSelectPanel: PropTypes.string,
|
||||||
|
focusOnOpen: PropTypes.bool,
|
||||||
|
onKeyDown: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
inputReadOnly: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
const { value, format } = props
|
||||||
|
this.state = {
|
||||||
|
str: value && value.format(format) || '',
|
||||||
|
invalid: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
if (this.props.focusOnOpen) {
|
||||||
|
// Wait one frame for the panel to be positioned before focusing
|
||||||
|
const requestAnimationFrame = (window.requestAnimationFrame || window.setTimeout)
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.refs.input.focus()
|
||||||
|
this.refs.input.select()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps (nextProps) {
|
||||||
|
const { value, format } = nextProps
|
||||||
|
this.setState({
|
||||||
|
str: value && value.format(format) || '',
|
||||||
|
invalid: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onInputChange = (event) => {
|
||||||
|
const str = event.target.value
|
||||||
|
this.setState({
|
||||||
|
str,
|
||||||
|
})
|
||||||
|
const {
|
||||||
|
format, hourOptions, minuteOptions, secondOptions,
|
||||||
|
disabledHours, disabledMinutes,
|
||||||
|
disabledSeconds, onChange, allowEmpty,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
if (str) {
|
||||||
|
const originalValue = this.props.value
|
||||||
|
const value = this.getProtoValue().clone()
|
||||||
|
const parsed = moment(str, format, true)
|
||||||
|
if (!parsed.isValid()) {
|
||||||
|
this.setState({
|
||||||
|
invalid: true,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value.hour(parsed.hour()).minute(parsed.minute()).second(parsed.second())
|
||||||
|
|
||||||
|
// if time value not allowed, response warning.
|
||||||
|
if (
|
||||||
|
hourOptions.indexOf(value.hour()) < 0 ||
|
||||||
|
minuteOptions.indexOf(value.minute()) < 0 ||
|
||||||
|
secondOptions.indexOf(value.second()) < 0
|
||||||
|
) {
|
||||||
|
this.setState({
|
||||||
|
invalid: true,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if time value is disabled, response warning.
|
||||||
|
const disabledHourOptions = disabledHours()
|
||||||
|
const disabledMinuteOptions = disabledMinutes(value.hour())
|
||||||
|
const disabledSecondOptions = disabledSeconds(value.hour(), value.minute())
|
||||||
|
if (
|
||||||
|
(disabledHourOptions && disabledHourOptions.indexOf(value.hour()) >= 0) ||
|
||||||
|
(disabledMinuteOptions && disabledMinuteOptions.indexOf(value.minute()) >= 0) ||
|
||||||
|
(disabledSecondOptions && disabledSecondOptions.indexOf(value.second()) >= 0)
|
||||||
|
) {
|
||||||
|
this.setState({
|
||||||
|
invalid: true,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (originalValue) {
|
||||||
|
if (
|
||||||
|
originalValue.hour() !== value.hour() ||
|
||||||
|
originalValue.minute() !== value.minute() ||
|
||||||
|
originalValue.second() !== value.second()
|
||||||
|
) {
|
||||||
|
// keep other fields for rc-calendar
|
||||||
|
const changedValue = originalValue.clone()
|
||||||
|
changedValue.hour(value.hour())
|
||||||
|
changedValue.minute(value.minute())
|
||||||
|
changedValue.second(value.second())
|
||||||
|
onChange(changedValue)
|
||||||
|
}
|
||||||
|
} else if (originalValue !== value) {
|
||||||
|
onChange(value)
|
||||||
|
}
|
||||||
|
} else if (allowEmpty) {
|
||||||
|
onChange(null)
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
invalid: true,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
invalid: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown = (e) => {
|
||||||
|
const { onEsc, onKeyDown } = this.props
|
||||||
|
if (e.keyCode === 27) {
|
||||||
|
onEsc()
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
onClear = () => {
|
||||||
|
this.setState({ str: '' })
|
||||||
|
this.props.onClear()
|
||||||
|
}
|
||||||
|
|
||||||
|
getClearButton () {
|
||||||
|
const { prefixCls, allowEmpty } = this.props
|
||||||
|
if (!allowEmpty) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return (<a
|
||||||
|
className={`${prefixCls}-clear-btn`}
|
||||||
|
role='button'
|
||||||
|
title={this.props.clearText}
|
||||||
|
onMouseDown={this.onClear}
|
||||||
|
/>)
|
||||||
|
}
|
||||||
|
|
||||||
|
getProtoValue () {
|
||||||
|
return this.props.value || this.props.defaultOpenValue
|
||||||
|
}
|
||||||
|
|
||||||
|
getInput () {
|
||||||
|
const { prefixCls, placeholder, inputReadOnly } = this.props
|
||||||
|
const { invalid, str } = this.state
|
||||||
|
const invalidClass = invalid ? `${prefixCls}-input-invalid` : ''
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
className={`${prefixCls}-input ${invalidClass}`}
|
||||||
|
ref='input'
|
||||||
|
onKeyDown={this.onKeyDown}
|
||||||
|
value={str}
|
||||||
|
placeholder={placeholder}
|
||||||
|
onChange={this.onInputChange}
|
||||||
|
readOnly={!!inputReadOnly}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { prefixCls } = this.props
|
||||||
|
return (
|
||||||
|
<div className={`${prefixCls}-input-wrap`}>
|
||||||
|
{this.getInput()}
|
||||||
|
{this.getClearButton()}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Header
|
||||||
|
</script>
|
188
components/vc-time-picker/Panel.vue
Normal file
188
components/vc-time-picker/Panel.vue
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
<script>
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import Header from './Header'
|
||||||
|
import Combobox from './Combobox'
|
||||||
|
import moment from 'moment'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
|
function noop () {
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateOptions (length, disabledOptions, hideDisabledOptions, step = 1) {
|
||||||
|
const arr = []
|
||||||
|
for (let value = 0; value < length; value += step) {
|
||||||
|
if (!disabledOptions || disabledOptions.indexOf(value) < 0 || !hideDisabledOptions) {
|
||||||
|
arr.push(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
class Panel extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
clearText: PropTypes.string,
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
className: PropTypes.string,
|
||||||
|
defaultOpenValue: PropTypes.object,
|
||||||
|
value: PropTypes.object,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
format: PropTypes.string,
|
||||||
|
inputReadOnly: PropTypes.bool,
|
||||||
|
disabledHours: PropTypes.func,
|
||||||
|
disabledMinutes: PropTypes.func,
|
||||||
|
disabledSeconds: PropTypes.func,
|
||||||
|
hideDisabledOptions: PropTypes.bool,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
onEsc: PropTypes.func,
|
||||||
|
allowEmpty: PropTypes.bool,
|
||||||
|
showHour: PropTypes.bool,
|
||||||
|
showMinute: PropTypes.bool,
|
||||||
|
showSecond: PropTypes.bool,
|
||||||
|
onClear: PropTypes.func,
|
||||||
|
use12Hours: PropTypes.bool,
|
||||||
|
hourStep: PropTypes.number,
|
||||||
|
minuteStep: PropTypes.number,
|
||||||
|
secondStep: PropTypes.number,
|
||||||
|
addon: PropTypes.func,
|
||||||
|
focusOnOpen: PropTypes.bool,
|
||||||
|
onKeyDown: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
prefixCls: 'rc-time-picker-panel',
|
||||||
|
onChange: noop,
|
||||||
|
onClear: noop,
|
||||||
|
disabledHours: noop,
|
||||||
|
disabledMinutes: noop,
|
||||||
|
disabledSeconds: noop,
|
||||||
|
defaultOpenValue: moment(),
|
||||||
|
use12Hours: false,
|
||||||
|
addon: noop,
|
||||||
|
onKeyDown: noop,
|
||||||
|
inputReadOnly: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
value: props.value,
|
||||||
|
selectionRange: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps (nextProps) {
|
||||||
|
const value = nextProps.value
|
||||||
|
if (value) {
|
||||||
|
this.setState({
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange = (newValue) => {
|
||||||
|
this.setState({ value: newValue })
|
||||||
|
this.props.onChange(newValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
onCurrentSelectPanelChange = (currentSelectPanel) => {
|
||||||
|
this.setState({ currentSelectPanel })
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/ant-design/ant-design/issues/5829
|
||||||
|
close () {
|
||||||
|
this.props.onEsc()
|
||||||
|
}
|
||||||
|
|
||||||
|
disabledHours = () => {
|
||||||
|
const { use12Hours, disabledHours } = this.props
|
||||||
|
let disabledOptions = disabledHours()
|
||||||
|
if (use12Hours && Array.isArray(disabledOptions)) {
|
||||||
|
if (this.isAM()) {
|
||||||
|
disabledOptions = disabledOptions.filter(h => h < 12).map(h => (h === 0 ? 12 : h))
|
||||||
|
} else {
|
||||||
|
disabledOptions = disabledOptions.map(h => (h === 12 ? 12 : h - 12))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return disabledOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
isAM () {
|
||||||
|
const value = (this.state.value || this.props.defaultOpenValue)
|
||||||
|
return value.hour() >= 0 && value.hour() < 12
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const {
|
||||||
|
prefixCls, className, placeholder, disabledMinutes,
|
||||||
|
disabledSeconds, hideDisabledOptions, allowEmpty, showHour, showMinute, showSecond,
|
||||||
|
format, defaultOpenValue, clearText, onEsc, addon, use12Hours, onClear,
|
||||||
|
focusOnOpen, onKeyDown, hourStep, minuteStep, secondStep, inputReadOnly,
|
||||||
|
} = this.props
|
||||||
|
const {
|
||||||
|
value, currentSelectPanel,
|
||||||
|
} = this.state
|
||||||
|
const disabledHourOptions = this.disabledHours()
|
||||||
|
const disabledMinuteOptions = disabledMinutes(value ? value.hour() : null)
|
||||||
|
const disabledSecondOptions = disabledSeconds(value ? value.hour() : null,
|
||||||
|
value ? value.minute() : null)
|
||||||
|
const hourOptions = generateOptions(
|
||||||
|
24, disabledHourOptions, hideDisabledOptions, hourStep
|
||||||
|
)
|
||||||
|
const minuteOptions = generateOptions(
|
||||||
|
60, disabledMinuteOptions, hideDisabledOptions, minuteStep
|
||||||
|
)
|
||||||
|
const secondOptions = generateOptions(
|
||||||
|
60, disabledSecondOptions, hideDisabledOptions, secondStep
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classNames({ [`${prefixCls}-inner`]: true, [className]: !!className })}>
|
||||||
|
<Header
|
||||||
|
clearText={clearText}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
defaultOpenValue={defaultOpenValue}
|
||||||
|
value={value}
|
||||||
|
currentSelectPanel={currentSelectPanel}
|
||||||
|
onEsc={onEsc}
|
||||||
|
format={format}
|
||||||
|
placeholder={placeholder}
|
||||||
|
hourOptions={hourOptions}
|
||||||
|
minuteOptions={minuteOptions}
|
||||||
|
secondOptions={secondOptions}
|
||||||
|
disabledHours={this.disabledHours}
|
||||||
|
disabledMinutes={disabledMinutes}
|
||||||
|
disabledSeconds={disabledSeconds}
|
||||||
|
onChange={this.onChange}
|
||||||
|
onClear={onClear}
|
||||||
|
allowEmpty={allowEmpty}
|
||||||
|
focusOnOpen={focusOnOpen}
|
||||||
|
onKeyDown={onKeyDown}
|
||||||
|
inputReadOnly={inputReadOnly}
|
||||||
|
/>
|
||||||
|
<Combobox
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
value={value}
|
||||||
|
defaultOpenValue={defaultOpenValue}
|
||||||
|
format={format}
|
||||||
|
onChange={this.onChange}
|
||||||
|
showHour={showHour}
|
||||||
|
showMinute={showMinute}
|
||||||
|
showSecond={showSecond}
|
||||||
|
hourOptions={hourOptions}
|
||||||
|
minuteOptions={minuteOptions}
|
||||||
|
secondOptions={secondOptions}
|
||||||
|
disabledHours={this.disabledHours}
|
||||||
|
disabledMinutes={disabledMinutes}
|
||||||
|
disabledSeconds={disabledSeconds}
|
||||||
|
onCurrentSelectPanelChange={this.onCurrentSelectPanelChange}
|
||||||
|
use12Hours={use12Hours}
|
||||||
|
isAM={this.isAM()}
|
||||||
|
/>
|
||||||
|
{addon(this)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Panel
|
||||||
|
</script>
|
131
components/vc-time-picker/Select.vue
Normal file
131
components/vc-time-picker/Select.vue
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
<script>
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
|
||||||
|
const scrollTo = (element, to, duration) => {
|
||||||
|
const requestAnimationFrame = window.requestAnimationFrame ||
|
||||||
|
function requestAnimationFrameTimeout () {
|
||||||
|
return setTimeout(arguments[0], 10)
|
||||||
|
}
|
||||||
|
// jump to target if duration zero
|
||||||
|
if (duration <= 0) {
|
||||||
|
element.scrollTop = to
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const difference = to - element.scrollTop
|
||||||
|
const perTick = difference / duration * 10
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
element.scrollTop = element.scrollTop + perTick
|
||||||
|
if (element.scrollTop === to) return
|
||||||
|
scrollTo(element, to, duration - 10)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
class Select extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
options: PropTypes.array,
|
||||||
|
selectedIndex: PropTypes.number,
|
||||||
|
type: PropTypes.string,
|
||||||
|
onSelect: PropTypes.func,
|
||||||
|
onMouseEnter: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
active: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
// jump to selected option
|
||||||
|
this.scrollToSelected(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate (prevProps) {
|
||||||
|
// smooth scroll to selected option
|
||||||
|
if (prevProps.selectedIndex !== this.props.selectedIndex) {
|
||||||
|
this.scrollToSelected(120)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelect = (value) => {
|
||||||
|
const { onSelect, type } = this.props
|
||||||
|
onSelect(type, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptions () {
|
||||||
|
const { options, selectedIndex, prefixCls } = this.props
|
||||||
|
return options.map((item, index) => {
|
||||||
|
const cls = classnames({
|
||||||
|
[`${prefixCls}-select-option-selected`]: selectedIndex === index,
|
||||||
|
[`${prefixCls}-select-option-disabled`]: item.disabled,
|
||||||
|
})
|
||||||
|
let onclick = null
|
||||||
|
if (!item.disabled) {
|
||||||
|
onclick = this.onSelect.bind(this, item.value)
|
||||||
|
}
|
||||||
|
return (<li
|
||||||
|
className={cls}
|
||||||
|
key={index}
|
||||||
|
onClick={onclick}
|
||||||
|
disabled={item.disabled}
|
||||||
|
>
|
||||||
|
{item.value}
|
||||||
|
</li>)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollToSelected (duration) {
|
||||||
|
// move to selected item
|
||||||
|
const select = ReactDom.findDOMNode(this)
|
||||||
|
const list = ReactDom.findDOMNode(this.list)
|
||||||
|
if (!list) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let index = this.props.selectedIndex
|
||||||
|
if (index < 0) {
|
||||||
|
index = 0
|
||||||
|
}
|
||||||
|
const topOption = list.children[index]
|
||||||
|
const to = topOption.offsetTop
|
||||||
|
scrollTo(select, to, duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseEnter = (e) => {
|
||||||
|
this.setState({ active: true })
|
||||||
|
this.props.onMouseEnter(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseLeave = () => {
|
||||||
|
this.setState({ active: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
saveList = (node) => {
|
||||||
|
this.list = node
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
if (this.props.options.length === 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const { prefixCls } = this.props
|
||||||
|
const cls = classnames({
|
||||||
|
[`${prefixCls}-select`]: 1,
|
||||||
|
[`${prefixCls}-select-active`]: this.state.active,
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cls}
|
||||||
|
onMouseEnter={this.handleMouseEnter}
|
||||||
|
onMouseLeave={this.handleMouseLeave}
|
||||||
|
>
|
||||||
|
<ul ref={this.saveList}>{this.getOptions()}</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Select
|
||||||
|
</script>
|
300
components/vc-time-picker/TimePicker.vue
Normal file
300
components/vc-time-picker/TimePicker.vue
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
<script>
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import Trigger from 'rc-trigger'
|
||||||
|
import Panel from './Panel'
|
||||||
|
import placements from './placements'
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
|
function noop () {
|
||||||
|
}
|
||||||
|
|
||||||
|
function refFn (field, component) {
|
||||||
|
this[field] = component
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Picker extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
clearText: PropTypes.string,
|
||||||
|
value: PropTypes.object,
|
||||||
|
defaultOpenValue: PropTypes.object,
|
||||||
|
inputReadOnly: PropTypes.bool,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
allowEmpty: PropTypes.bool,
|
||||||
|
defaultValue: PropTypes.object,
|
||||||
|
open: PropTypes.bool,
|
||||||
|
defaultOpen: PropTypes.bool,
|
||||||
|
align: PropTypes.object,
|
||||||
|
placement: PropTypes.any,
|
||||||
|
transitionName: PropTypes.string,
|
||||||
|
getPopupContainer: PropTypes.func,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
format: PropTypes.string,
|
||||||
|
showHour: PropTypes.bool,
|
||||||
|
showMinute: PropTypes.bool,
|
||||||
|
showSecond: PropTypes.bool,
|
||||||
|
style: PropTypes.object,
|
||||||
|
className: PropTypes.string,
|
||||||
|
popupClassName: PropTypes.string,
|
||||||
|
disabledHours: PropTypes.func,
|
||||||
|
disabledMinutes: PropTypes.func,
|
||||||
|
disabledSeconds: PropTypes.func,
|
||||||
|
hideDisabledOptions: PropTypes.bool,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
onOpen: PropTypes.func,
|
||||||
|
onClose: PropTypes.func,
|
||||||
|
onFocus: PropTypes.func,
|
||||||
|
onBlur: PropTypes.func,
|
||||||
|
addon: PropTypes.func,
|
||||||
|
name: PropTypes.string,
|
||||||
|
autoComplete: PropTypes.string,
|
||||||
|
use12Hours: PropTypes.bool,
|
||||||
|
hourStep: PropTypes.number,
|
||||||
|
minuteStep: PropTypes.number,
|
||||||
|
secondStep: PropTypes.number,
|
||||||
|
focusOnOpen: PropTypes.bool,
|
||||||
|
onKeyDown: PropTypes.func,
|
||||||
|
autoFocus: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
clearText: 'clear',
|
||||||
|
prefixCls: 'rc-time-picker',
|
||||||
|
defaultOpen: false,
|
||||||
|
inputReadOnly: false,
|
||||||
|
style: {},
|
||||||
|
className: '',
|
||||||
|
popupClassName: '',
|
||||||
|
align: {},
|
||||||
|
defaultOpenValue: moment(),
|
||||||
|
allowEmpty: true,
|
||||||
|
showHour: true,
|
||||||
|
showMinute: true,
|
||||||
|
showSecond: true,
|
||||||
|
disabledHours: noop,
|
||||||
|
disabledMinutes: noop,
|
||||||
|
disabledSeconds: noop,
|
||||||
|
hideDisabledOptions: false,
|
||||||
|
placement: 'bottomLeft',
|
||||||
|
onChange: noop,
|
||||||
|
onOpen: noop,
|
||||||
|
onClose: noop,
|
||||||
|
onFocus: noop,
|
||||||
|
onBlur: noop,
|
||||||
|
addon: noop,
|
||||||
|
use12Hours: false,
|
||||||
|
focusOnOpen: false,
|
||||||
|
onKeyDown: noop,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
this.saveInputRef = refFn.bind(this, 'picker')
|
||||||
|
this.savePanelRef = refFn.bind(this, 'panelInstance')
|
||||||
|
const { defaultOpen, defaultValue, open = defaultOpen, value = defaultValue } = props
|
||||||
|
this.state = {
|
||||||
|
open,
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps (nextProps) {
|
||||||
|
const { value, open } = nextProps
|
||||||
|
if ('value' in nextProps) {
|
||||||
|
this.setState({
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (open !== undefined) {
|
||||||
|
this.setState({ open })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPanelChange = (value) => {
|
||||||
|
this.setValue(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
onPanelClear = () => {
|
||||||
|
this.setValue(null)
|
||||||
|
this.setOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
onVisibleChange = (open) => {
|
||||||
|
this.setOpen(open)
|
||||||
|
}
|
||||||
|
|
||||||
|
onEsc = () => {
|
||||||
|
this.setOpen(false)
|
||||||
|
this.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown = (e) => {
|
||||||
|
if (e.keyCode === 40) {
|
||||||
|
this.setOpen(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue (value) {
|
||||||
|
if (!('value' in this.props)) {
|
||||||
|
this.setState({
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.props.onChange(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
getFormat () {
|
||||||
|
const { format, showHour, showMinute, showSecond, use12Hours } = this.props
|
||||||
|
if (format) {
|
||||||
|
return format
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use12Hours) {
|
||||||
|
const fmtString = ([
|
||||||
|
showHour ? 'h' : '',
|
||||||
|
showMinute ? 'mm' : '',
|
||||||
|
showSecond ? 'ss' : '',
|
||||||
|
].filter(item => !!item).join(':'))
|
||||||
|
|
||||||
|
return fmtString.concat(' a')
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
showHour ? 'HH' : '',
|
||||||
|
showMinute ? 'mm' : '',
|
||||||
|
showSecond ? 'ss' : '',
|
||||||
|
].filter(item => !!item).join(':')
|
||||||
|
}
|
||||||
|
|
||||||
|
getPanelElement () {
|
||||||
|
const {
|
||||||
|
prefixCls, placeholder, disabledHours,
|
||||||
|
disabledMinutes, disabledSeconds, hideDisabledOptions, inputReadOnly,
|
||||||
|
allowEmpty, showHour, showMinute, showSecond, defaultOpenValue, clearText,
|
||||||
|
addon, use12Hours, focusOnOpen, onKeyDown, hourStep, minuteStep, secondStep,
|
||||||
|
} = this.props
|
||||||
|
return (
|
||||||
|
<Panel
|
||||||
|
clearText={clearText}
|
||||||
|
prefixCls={`${prefixCls}-panel`}
|
||||||
|
ref={this.savePanelRef}
|
||||||
|
value={this.state.value}
|
||||||
|
inputReadOnly={inputReadOnly}
|
||||||
|
onChange={this.onPanelChange}
|
||||||
|
onClear={this.onPanelClear}
|
||||||
|
defaultOpenValue={defaultOpenValue}
|
||||||
|
showHour={showHour}
|
||||||
|
showMinute={showMinute}
|
||||||
|
showSecond={showSecond}
|
||||||
|
onEsc={this.onEsc}
|
||||||
|
allowEmpty={allowEmpty}
|
||||||
|
format={this.getFormat()}
|
||||||
|
placeholder={placeholder}
|
||||||
|
disabledHours={disabledHours}
|
||||||
|
disabledMinutes={disabledMinutes}
|
||||||
|
disabledSeconds={disabledSeconds}
|
||||||
|
hideDisabledOptions={hideDisabledOptions}
|
||||||
|
use12Hours={use12Hours}
|
||||||
|
hourStep={hourStep}
|
||||||
|
minuteStep={minuteStep}
|
||||||
|
secondStep={secondStep}
|
||||||
|
addon={addon}
|
||||||
|
focusOnOpen={focusOnOpen}
|
||||||
|
onKeyDown={onKeyDown}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getPopupClassName () {
|
||||||
|
const { showHour, showMinute, showSecond, use12Hours, prefixCls } = this.props
|
||||||
|
let popupClassName = this.props.popupClassName
|
||||||
|
// Keep it for old compatibility
|
||||||
|
if ((!showHour || !showMinute || !showSecond) && !use12Hours) {
|
||||||
|
popupClassName += ` ${prefixCls}-panel-narrow`
|
||||||
|
}
|
||||||
|
let selectColumnCount = 0
|
||||||
|
if (showHour) {
|
||||||
|
selectColumnCount += 1
|
||||||
|
}
|
||||||
|
if (showMinute) {
|
||||||
|
selectColumnCount += 1
|
||||||
|
}
|
||||||
|
if (showSecond) {
|
||||||
|
selectColumnCount += 1
|
||||||
|
}
|
||||||
|
if (use12Hours) {
|
||||||
|
selectColumnCount += 1
|
||||||
|
}
|
||||||
|
popupClassName += ` ${prefixCls}-panel-column-${selectColumnCount}`
|
||||||
|
return popupClassName
|
||||||
|
}
|
||||||
|
|
||||||
|
setOpen (open) {
|
||||||
|
const { onOpen, onClose } = this.props
|
||||||
|
if (this.state.open !== open) {
|
||||||
|
if (!('open' in this.props)) {
|
||||||
|
this.setState({ open })
|
||||||
|
}
|
||||||
|
if (open) {
|
||||||
|
onOpen({ open })
|
||||||
|
} else {
|
||||||
|
onClose({ open })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
focus () {
|
||||||
|
this.picker.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
blur () {
|
||||||
|
this.picker.blur()
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const {
|
||||||
|
prefixCls, placeholder, placement, align,
|
||||||
|
disabled, transitionName, style, className, getPopupContainer, name, autoComplete,
|
||||||
|
onFocus, onBlur, autoFocus, inputReadOnly,
|
||||||
|
} = this.props
|
||||||
|
const { open, value } = this.state
|
||||||
|
const popupClassName = this.getPopupClassName()
|
||||||
|
return (
|
||||||
|
<Trigger
|
||||||
|
prefixCls={`${prefixCls}-panel`}
|
||||||
|
popupClassName={popupClassName}
|
||||||
|
popup={this.getPanelElement()}
|
||||||
|
popupAlign={align}
|
||||||
|
builtinPlacements={placements}
|
||||||
|
popupPlacement={placement}
|
||||||
|
action={disabled ? [] : ['click']}
|
||||||
|
destroyPopupOnHide
|
||||||
|
getPopupContainer={getPopupContainer}
|
||||||
|
popupTransitionName={transitionName}
|
||||||
|
popupVisible={open}
|
||||||
|
onPopupVisibleChange={this.onVisibleChange}
|
||||||
|
>
|
||||||
|
<span className={`${prefixCls} ${className}`} style={style}>
|
||||||
|
<input
|
||||||
|
className={`${prefixCls}-input`}
|
||||||
|
ref={this.saveInputRef}
|
||||||
|
type='text'
|
||||||
|
placeholder={placeholder}
|
||||||
|
name={name}
|
||||||
|
onKeyDown={this.onKeyDown}
|
||||||
|
disabled={disabled}
|
||||||
|
value={value && value.format(this.getFormat()) || ''}
|
||||||
|
autoComplete={autoComplete}
|
||||||
|
onFocus={onFocus}
|
||||||
|
onBlur={onBlur}
|
||||||
|
autoFocus={autoFocus}
|
||||||
|
onChange={noop}
|
||||||
|
readOnly={!!inputReadOnly}
|
||||||
|
/>
|
||||||
|
<span className={`${prefixCls}-icon`}/>
|
||||||
|
</span>
|
||||||
|
</Trigger>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
14
components/vc-time-picker/assets/index.less
Normal file
14
components/vc-time-picker/assets/index.less
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
@prefixClass: rc-time-picker;
|
||||||
|
|
||||||
|
.@{prefixClass} {
|
||||||
|
display: inline-block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@import "./index/Picker";
|
||||||
|
@import "./index/Panel";
|
||||||
|
@import "./index/Header";
|
||||||
|
@import "./index/Select";
|
49
components/vc-time-picker/assets/index/Header.less
Normal file
49
components/vc-time-picker/assets/index/Header.less
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
.@{prefixClass}-panel {
|
||||||
|
&-input {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
cursor: auto;
|
||||||
|
line-height: 1.5;
|
||||||
|
outline: 0;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
|
||||||
|
&-wrap {
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
padding: 6px;
|
||||||
|
border-bottom: 1px solid #e9e9e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-invalid {
|
||||||
|
border-color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-clear-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 20px;
|
||||||
|
top: 6px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-clear-btn:after {
|
||||||
|
content: "x";
|
||||||
|
font-size: 12px;
|
||||||
|
color: #aaa;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 1;
|
||||||
|
width: 20px;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-clear-btn:hover:after {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
29
components/vc-time-picker/assets/index/Panel.less
Normal file
29
components/vc-time-picker/assets/index/Panel.less
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
.@{prefixClass}-panel {
|
||||||
|
z-index: 1070;
|
||||||
|
width: 170px;
|
||||||
|
position: absolute;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-inner {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
outline: none;
|
||||||
|
list-style: none;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: left;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 5px #ccc;
|
||||||
|
background-clip: padding-box;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-narrow {
|
||||||
|
max-width: 113px;
|
||||||
|
}
|
||||||
|
}
|
23
components/vc-time-picker/assets/index/Picker.less
Normal file
23
components/vc-time-picker/assets/index/Picker.less
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.@{prefixClass} {
|
||||||
|
&-input {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px 7px;
|
||||||
|
height: 28px;
|
||||||
|
cursor: text;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #666;
|
||||||
|
background-color: #fff;
|
||||||
|
background-image: none;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: border .2s cubic-bezier(0.645, 0.045, 0.355, 1), background .2s cubic-bezier(0.645, 0.045, 0.355, 1), box-shadow .2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
&[disabled] {
|
||||||
|
color: #ccc;
|
||||||
|
background: #f7f7f7;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
components/vc-time-picker/assets/index/Select.less
Normal file
63
components/vc-time-picker/assets/index/Select.less
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
.@{prefixClass}-panel-select {
|
||||||
|
float: left;
|
||||||
|
font-size: 12px;
|
||||||
|
border: 1px solid #e9e9e9;
|
||||||
|
border-width: 0 1px;
|
||||||
|
margin-left: -1px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 56px;
|
||||||
|
max-height: 144px;
|
||||||
|
overflow-y: auto;
|
||||||
|
position: relative; // Fix chrome weird render bug
|
||||||
|
|
||||||
|
&-active {
|
||||||
|
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%;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
box-sizing: content-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 0 0 16px;
|
||||||
|
width: 100%;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #edfaff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li&-option-selected {
|
||||||
|
background: #f7f7f7;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
li&-option-disabled {
|
||||||
|
color: #ccc;
|
||||||
|
&:hover {
|
||||||
|
background: transparent;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
components/vc-time-picker/index.js
Normal file
1
components/vc-time-picker/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './TimePicker'
|
35
components/vc-time-picker/placements.js
Normal file
35
components/vc-time-picker/placements.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
const autoAdjustOverflow = {
|
||||||
|
adjustX: 1,
|
||||||
|
adjustY: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetOffset = [0, 0]
|
||||||
|
|
||||||
|
const placements = {
|
||||||
|
bottomLeft: {
|
||||||
|
points: ['tl', 'tl'],
|
||||||
|
overflow: autoAdjustOverflow,
|
||||||
|
offset: [0, -3],
|
||||||
|
targetOffset,
|
||||||
|
},
|
||||||
|
bottomRight: {
|
||||||
|
points: ['tr', 'tr'],
|
||||||
|
overflow: autoAdjustOverflow,
|
||||||
|
offset: [0, -3],
|
||||||
|
targetOffset,
|
||||||
|
},
|
||||||
|
topRight: {
|
||||||
|
points: ['br', 'br'],
|
||||||
|
overflow: autoAdjustOverflow,
|
||||||
|
offset: [0, 3],
|
||||||
|
targetOffset,
|
||||||
|
},
|
||||||
|
topLeft: {
|
||||||
|
points: ['bl', 'bl'],
|
||||||
|
overflow: autoAdjustOverflow,
|
||||||
|
offset: [0, 3],
|
||||||
|
targetOffset,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default placements
|
@ -23,7 +23,7 @@ Affix | done
|
|||||||
Cascader | done
|
Cascader | done
|
||||||
BackTop | done
|
BackTop | done
|
||||||
Modal | done
|
Modal | done
|
||||||
Alert
|
Alert | done
|
||||||
Calendar
|
Calendar
|
||||||
DatePicker
|
DatePicker
|
||||||
TimePicker
|
TimePicker
|
||||||
|
6
package-lock.json
generated
6
package-lock.json
generated
@ -8032,9 +8032,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.20.1",
|
"version": "2.21.0",
|
||||||
"resolved": "http://registry.npm.taobao.org/moment/download/moment-2.20.1.tgz",
|
"resolved": "http://registry.npm.taobao.org/moment/download/moment-2.21.0.tgz",
|
||||||
"integrity": "sha1-1usaRsvMFKKy+UNBEsH/iQfzE/0="
|
"integrity": "sha1-KhFLUdKm7J5tg8+AP4OKh42KAjo="
|
||||||
},
|
},
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
@ -99,7 +99,7 @@
|
|||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"lodash.isequal": "^4.5.0",
|
"lodash.isequal": "^4.5.0",
|
||||||
"lodash.isplainobject": "^4.0.6",
|
"lodash.isplainobject": "^4.0.6",
|
||||||
"moment": "^2.20.1",
|
"moment": "^2.21.0",
|
||||||
"omit.js": "^1.0.0",
|
"omit.js": "^1.0.0",
|
||||||
"shallow-equal": "^1.0.0",
|
"shallow-equal": "^1.0.0",
|
||||||
"shallowequal": "^1.0.2",
|
"shallowequal": "^1.0.2",
|
||||||
|
Loading…
Reference in New Issue
Block a user