diff --git a/README.md b/README.md index e307c1f9..a970986a 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ API | showHour | Boolean | true | whether show hour | | | showMinute | Boolean | true | whether show minute | | showSecond | Boolean | true | whether show second | -| format | String | - | moment format | +| format | String or String[] | - | moment format | | disabledHours | Function | - | disabled hour options | | disabledMinutes | Function | - | disabled minute options | | disabledSeconds | Function | - | disabled second options | diff --git a/examples/multiFormat.html b/examples/multiFormat.html new file mode 100644 index 00000000..e69de29b diff --git a/examples/multiFormat.js b/examples/multiFormat.js new file mode 100644 index 00000000..3d1eab2a --- /dev/null +++ b/examples/multiFormat.js @@ -0,0 +1,22 @@ +/* eslint no-console:0 */ + +import 'rc-time-picker/assets/index.less'; + +import React from 'react'; +import ReactDom from 'react-dom'; + +import moment from 'moment'; + +import TimePicker from 'rc-time-picker'; + +const format = ['h:mm a', 'h:mm a', 'HH:mm a', 'h:mm', 'HH:mm', 'hhmm', 'HHmm']; + +const now = moment().hour(3).minute(0); + +ReactDom.render( + , + document.getElementById('__react-content') +); diff --git a/rc-time-picker.d.ts b/rc-time-picker.d.ts index c94a516b..33d10a39 100644 --- a/rc-time-picker.d.ts +++ b/rc-time-picker.d.ts @@ -1,43 +1,43 @@ -declare module "rc-time-picker" { - import { Moment } from "moment"; - import * as React from "react"; +declare module 'rc-time-picker' { + import { Moment } from 'moment'; + import * as React from 'react'; - type TimePickerProps = { - prefixCls?: String; - clearText?: String; - disabled?: Boolean; - allowEmpty?: Boolean; - open?: Boolean; - defaultValue?: Moment; - defaultOpenValue?: Moment; - value?: Moment; - placeholder?: String; - className?: String; - id?: String; - popupClassName?: String; - showHour?: Boolean; - showMinute?: Boolean; - showSecond?: Boolean; - format?: String; - disabledHours?: Function; - disabledMinutes?: Function; - disabledSeconds?: Function; - use12Hours?: Boolean; - hideDisabledOptions?: Boolean; - onChange?: Function; - addon?: Function; - placement?: String; - transitionName?: String; - name?: String; - onOpen?: Function; - onClose?: Function; - hourStep?: Number; - minuteStep?: Number; - secondStep?: Number; - focusOnOpen?: Boolean; - inputReadOnly?: Boolean; + interface ITimePickerProps { + prefixCls?: string; + clearText?: string; + disabled?: boolean; + allowEmpty?: boolean; + open?: boolean; + defaultValue?: moment; + defaultOpenValue?: moment; + value?: moment; + placeholder?: string; + className?: string; + id?: string; + popupClassName?: string; + showHour?: boolean; + showMinute?: boolean; + showSecond?: boolean; + format?: string; + disabledHours?: function; + disabledMinutes?: function; + disabledSeconds?: function; + use12Hours?: boolean; + hideDisabledOptions?: boolean; + onChange?: function; + addon?: function; + placement?: string; + transitionName?: string; + name?: string; + onOpen?: function; + onClose?: function; + hourStep?: number; + minuteStep?: number; + secondStep?: number; + focusOnOpen?: boolean; + inputReadOnly?: noolean; inputIcon?: React.ReactNode; clearIcon?: React.ReactNode; - }; + } export default class TimePicker extends React.Component {} } diff --git a/src/Combobox.jsx b/src/Combobox.jsx index cb29161d..7979eb0b 100644 --- a/src/Combobox.jsx +++ b/src/Combobox.jsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import Select from './Select'; +import { getTimeFormat } from './util'; const formatOption = (option, disabledOptions) => { let value = `${option}`; @@ -21,7 +22,7 @@ const formatOption = (option, disabledOptions) => { class Combobox extends Component { static propTypes = { - format: PropTypes.string, + format: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]), defaultOpenValue: PropTypes.object, prefixCls: PropTypes.string, value: PropTypes.object, @@ -172,13 +173,14 @@ class Combobox extends Component { } getAMPMSelect() { - const { prefixCls, use12Hours, format, isAM } = this.props; + const { prefixCls, use12Hours, isAM, format } = this.props; + const timeFormat = getTimeFormat(format); 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 => (timeFormat.match(/\sA/) ? c.toUpperCase() : c)) .map(c => ({ value: c })); const selected = isAM ? 0 : 1; diff --git a/src/Header.jsx b/src/Header.jsx index 03916bdf..f1fe051d 100644 --- a/src/Header.jsx +++ b/src/Header.jsx @@ -1,10 +1,11 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import moment from 'moment'; +import { formatTime } from './util'; class Header extends Component { static propTypes = { - format: PropTypes.string, + format: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]), prefixCls: PropTypes.string, disabledDate: PropTypes.func, placeholder: PropTypes.string, @@ -36,7 +37,7 @@ class Header extends Component { super(props); const { value, format } = props; this.state = { - str: (value && value.format(format)) || '', + str: formatTime(value, format), invalid: false, }; } @@ -56,7 +57,7 @@ class Header extends Component { componentWillReceiveProps(nextProps) { const { value, format } = nextProps; this.setState({ - str: (value && value.format(format)) || '', + str: formatTime(value, format), invalid: false, }); } diff --git a/src/Panel.jsx b/src/Panel.jsx index d57ee999..a27c453f 100644 --- a/src/Panel.jsx +++ b/src/Panel.jsx @@ -38,7 +38,7 @@ class Panel extends Component { defaultOpenValue: PropTypes.object, value: PropTypes.object, placeholder: PropTypes.string, - format: PropTypes.string, + format: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]), inputReadOnly: PropTypes.bool, disabledHours: PropTypes.func, disabledMinutes: PropTypes.func, diff --git a/src/TimePicker.jsx b/src/TimePicker.jsx index 47daa1f3..a60af3cc 100644 --- a/src/TimePicker.jsx +++ b/src/TimePicker.jsx @@ -5,6 +5,7 @@ import Trigger from 'rc-trigger'; import moment from 'moment'; import Panel from './Panel'; import placements from './placements'; +import { formatTime } from './util'; function noop() {} @@ -29,7 +30,7 @@ export default class Picker extends Component { transitionName: PropTypes.string, getPopupContainer: PropTypes.func, placeholder: PropTypes.string, - format: PropTypes.string, + format: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]), showHour: PropTypes.bool, showMinute: PropTypes.bool, showSecond: PropTypes.bool, @@ -330,7 +331,7 @@ export default class Picker extends Component { name={name} onKeyDown={this.onKeyDown} disabled={disabled} - value={(value && value.format(this.getFormat())) || ''} + value={formatTime(value, this.getFormat())} autoComplete={autoComplete} onFocus={onFocus} onBlur={onBlur} diff --git a/src/util/index.js b/src/util/index.js new file mode 100644 index 00000000..0fc3d00a --- /dev/null +++ b/src/util/index.js @@ -0,0 +1,13 @@ +export function getTimeFormat(format) { + if (Array.isArray(format)) { + return format.length ? format[0] : undefined; + } + return format; +} + +export function formatTime(value, format) { + if (!value) { + return ''; + } + return value.format(getTimeFormat(format)); +} diff --git a/tests/TimePicker.spec.jsx b/tests/TimePicker.spec.jsx index c269278a..d42ce118 100644 --- a/tests/TimePicker.spec.jsx +++ b/tests/TimePicker.spec.jsx @@ -3,7 +3,7 @@ import React from 'react'; import { mount } from 'enzyme'; import moment from 'moment'; import TimePicker from '../src/TimePicker'; -import { clickInput, clickSelectItem, matchValue } from './util'; +import { clickInput, clickSelectItem, matchValue, findHeader } from './util'; describe('TimePicker', () => { let container; @@ -180,4 +180,33 @@ describe('TimePicker', () => { expect(blur).toBeTruthy(); }); }); + + describe('time formats', () => { + it('supports single format', async () => { + const picker = renderPickerWithoutSeconds({ + format: 'h:mm a', + }); + + clickInput(picker); + setTimeout(100); + findHeader(picker).simulate('change', { target: { value: '8:34 am' } }); + setTimeout(100); + matchValue(picker, '8:34 am'); + }); + + it('supports an array of formats', async () => { + const picker = renderPickerWithoutSeconds({ + format: ['h:mm', 'h:mm a'], + }); + + clickInput(picker); + setTimeout(100); + findHeader(picker).simulate('change', { target: { value: '8:34' } }); + setTimeout(100); + matchValue(picker, '8:34'); + findHeader(picker).simulate('change', { target: { value: '8:34 pm' } }); + setTimeout(100); + matchValue(picker, '8:34'); + }); + }); });