| value | moment | null | current value |
| placeholder | String | '' | time input's placeholder |
| showHour | Boolean | whether show hour | |
-| showMinute | Boolean | whether show minute | |
+| showMinute | Boolean | whether show minute | |
| showSecond | Boolean | whether show second | |
| format | String | | |
| disabledHours | Function | disabled hour options | |
| disabledMinutes | Function | disabled minute options | |
| disabledSeconds | Function | disabled second options | |
+| use12Hours | Boolean | 12 hours display mode | |
| hideDisabledOptions | Boolean | whether hide disabled options | |
| onChange | Function | null | called when select a different value |
| addon | Function | nothing | called from timepicker panel to render some addon to its bottom, like an OK button. Receives panel instance as parameter, to be able to close it like `panel.close()`.|
--- /dev/null
+/* 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';
+
+const now = moment().hour(0).minute(0);
+
+function onChange(value) {
+ console.log(value && value.format(format));
+}
+
+ReactDom.render(
+ <TimePicker
+ showSecond={false}
+ defaultValue={now}
+ className="xxx"
+ onChange={onChange}
+ format={format}
+ use12Hours
+ />,
+ document.getElementById('__react-content')
+);
disabledMinutes: PropTypes.func,
disabledSeconds: PropTypes.func,
onCurrentSelectPanelChange: PropTypes.func,
+ use12Hours: PropTypes.bool,
},
onItemChange(type, itemValue) {
- const { onChange, defaultOpenValue } = this.props;
+ const { onChange, defaultOpenValue, use12Hours } = this.props;
const value = (this.props.value || defaultOpenValue).clone();
+
if (type === 'hour') {
- value.hour(itemValue);
+ if (use12Hours) {
+ if (this.isAM()) {
+ value.hour(+itemValue % 12);
+ } else {
+ value.hour((+itemValue % 12) + 12);
+ }
+ } else {
+ value.hour(+itemValue);
+ }
} else if (type === 'minute') {
- value.minute(itemValue);
+ 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);
+ value.second(+itemValue);
}
onChange(value);
},
},
getHourSelect(hour) {
- const { prefixCls, hourOptions, disabledHours, showHour } = this.props;
+ 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={hourOptions.map(option => formatOption(option, disabledOptions))}
- selectedIndex={hourOptions.indexOf(hour)}
+ options={hourOptionsAdj.map(option => formatOption(option, disabledOptions))}
+ selectedIndex={hourOptionsAdj.indexOf(hourAdj)}
type="hour"
onSelect={this.onItemChange}
onMouseEnter={this.onEnterSelectPanel.bind(this, 'hour')}
);
},
+ 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.isAM() ? 0 : 1;
+
+ return (
+ <Select
+ prefixCls={prefixCls}
+ options={AMPMOptions}
+ selectedIndex={selected}
+ type="ampm"
+ onSelect={this.onItemChange}
+ onMouseEnter={this.onEnterSelectPanel.bind(this, 'ampm')}
+ />
+ );
+ },
+
+ isAM() {
+ const { value } = this.props;
+ return value.hour() >= 0 && value.hour() < 12;
+ },
+
render() {
const { prefixCls, defaultOpenValue } = this.props;
const value = this.props.value || defaultOpenValue;
{this.getHourSelect(value.hour())}
{this.getMinuteSelect(value.minute())}
{this.getSecondSelect(value.second())}
+ {this.getAMPMSelect(value.hour())}
</div>
);
},
showMinute: PropTypes.bool,
showSecond: PropTypes.bool,
onClear: PropTypes.func,
+ use12Hours: PropTypes.bool,
addon: PropTypes.func,
},
disabledMinutes: noop,
disabledSeconds: noop,
defaultOpenValue: moment(),
+ use12Hours: false,
addon: noop,
};
},
const {
prefixCls, className, placeholder, disabledHours, disabledMinutes,
disabledSeconds, hideDisabledOptions, allowEmpty, showHour, showMinute, showSecond,
- format, defaultOpenValue, clearText, onEsc, addon,
+ format, defaultOpenValue, clearText, onEsc, addon, use12Hours,
} = this.props;
const {
value, currentSelectPanel,
disabledMinutes={disabledMinutes}
disabledSeconds={disabledSeconds}
onCurrentSelectPanelChange={this.onCurrentSelectPanelChange}
+ use12Hours={use12Hours}
/>
{addon(this)}
</div>
});
let onclick = null;
if (!item.disabled) {
- onclick = this.onSelect.bind(this, +item.value);
+ onclick = this.onSelect.bind(this, item.value);
}
return (<li
className={cls}
addon: PropTypes.func,
name: PropTypes.string,
autoComplete: PropTypes.string,
+ use12Hours: PropTypes.bool,
},
getDefaultProps() {
onOpen: noop,
onClose: noop,
addon: noop,
+ use12Hours: false,
};
},
},
getFormat() {
- const { format, showHour, showMinute, showSecond } = this.props;
+ 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' : '',
prefixCls, placeholder, disabledHours,
disabledMinutes, disabledSeconds, hideDisabledOptions,
allowEmpty, showHour, showMinute, showSecond, defaultOpenValue, clearText,
- addon,
+ addon, use12Hours,
} = this.props;
return (
<Panel
disabledMinutes={disabledMinutes}
disabledSeconds={disabledSeconds}
hideDisabledOptions={hideDisabledOptions}
+ use12Hours={use12Hours}
addon={addon}
/>
);
});
});
});
+
+
+ describe('select in 12 hours mode', () => {
+ it('renders correctly', (done) => {
+ const picker = renderPicker({
+ use12Hours: true,
+ defaultValue: moment().hour(14).minute(0).second(0),
+ showSecond: false,
+ format: undefined,
+ });
+ expect(picker.state.open).not.to.be.ok();
+ const input = TestUtils.scryRenderedDOMComponentsWithClass(picker,
+ 'rc-time-picker-input')[0];
+ let selector;
+ async.series([(next) => {
+ expect(picker.state.open).to.be(false);
+
+ Simulate.click(input);
+ setTimeout(next, 100);
+ }, (next) => {
+ expect(picker.state.open).to.be(true);
+ selector = TestUtils.scryRenderedDOMComponentsWithClass(picker.panelInstance,
+ 'rc-time-picker-panel-select');
+ expect((input).value).to.be('2:00 pm');
+
+ setTimeout(next, 100);
+ }, (next) => {
+ expect(selector.length).to.be(3);
+
+ next();
+ }], () => {
+ done();
+ });
+ });
+
+
+ it('renders 12am correctly', (done) => {
+ const picker = renderPicker({
+ use12Hours: true,
+ defaultValue: moment().hour(0).minute(0).second(0),
+ showSecond: false,
+ format: undefined,
+ });
+ expect(picker.state.open).not.to.be.ok();
+ const input = TestUtils.scryRenderedDOMComponentsWithClass(picker,
+ 'rc-time-picker-input')[0];
+ let selector;
+ async.series([(next) => {
+ expect(picker.state.open).to.be(false);
+
+ Simulate.click(input);
+ setTimeout(next, 100);
+ }, (next) => {
+ expect(picker.state.open).to.be(true);
+ selector = TestUtils.scryRenderedDOMComponentsWithClass(picker.panelInstance,
+ 'rc-time-picker-panel-select');
+ setTimeout(next, 100);
+ }, (next) => {
+ expect(selector.length).to.be(3);
+
+ next();
+ }], () => {
+ done();
+ });
+ });
+
+
+ it('renders 5am correctly', (done) => {
+ const picker = renderPicker({
+ use12Hours: true,
+ defaultValue: moment().hour(0).minute(0).second(0),
+ showSecond: false,
+ format: undefined,
+ });
+ expect(picker.state.open).not.to.be.ok();
+ const input = TestUtils.scryRenderedDOMComponentsWithClass(picker,
+ 'rc-time-picker-input')[0];
+ let selector;
+ async.series([(next) => {
+ expect(picker.state.open).to.be(false);
+
+ Simulate.click(input);
+ setTimeout(next, 100);
+ }, (next) => {
+ expect(picker.state.open).to.be(true);
+ selector = TestUtils.scryRenderedDOMComponentsWithClass(picker.panelInstance,
+ 'rc-time-picker-panel-select')[0];
+ expect((input).value).to.be('12:00 am');
+ const option = selector.getElementsByTagName('li')[3];
+ Simulate.click(option);
+ setTimeout(next, 100);
+ }, (next) => {
+ expect((input).value).to.be('3:00 am');
+ next();
+ }], () => {
+ done();
+ });
+ });
+
+
+ it('renders 12am/pm correctly', (done) => {
+ const picker = renderPicker({
+ use12Hours: true,
+ defaultValue: moment().hour(0).minute(0).second(0),
+ showSecond: false,
+ format: undefined,
+ });
+ expect(picker.state.open).not.to.be.ok();
+ const input = TestUtils.scryRenderedDOMComponentsWithClass(picker,
+ 'rc-time-picker-input')[0];
+ let selector;
+ async.series([(next) => {
+ expect(picker.state.open).to.be(false);
+
+ Simulate.click(input);
+ setTimeout(next, 100);
+ }, (next) => {
+ expect(picker.state.open).to.be(true);
+ selector = TestUtils.scryRenderedDOMComponentsWithClass(picker.panelInstance,
+ 'rc-time-picker-panel-select')[2];
+ expect((input).value).to.be('12:00 am');
+ const option = selector.getElementsByTagName('li')[1];
+ Simulate.click(option);
+ setTimeout(next, 200);
+ }, (next) => {
+ expect((input).value).to.be('12:00 pm');
+ next();
+ }, (next) => {
+ Simulate.click(selector.getElementsByTagName('li')[0]);
+ setTimeout(next, 200);
+ }, (next) => {
+ expect((input).value).to.be('12:00 am');
+ next();
+ }], () => {
+ done();
+ });
+ });
+
+ it('renders uppercase AM correctly', (done) => {
+ const picker = renderPicker({
+ use12Hours: true,
+ defaultValue: moment().hour(0).minute(0).second(0),
+ showSecond: false,
+ format: 'h:mm A',
+ });
+ expect(picker.state.open).not.to.be.ok();
+ const input = TestUtils.scryRenderedDOMComponentsWithClass(picker,
+ 'rc-time-picker-input')[0];
+ let selector;
+ async.series([(next) => {
+ expect(picker.state.open).to.be(false);
+
+ Simulate.click(input);
+ setTimeout(next, 100);
+ }, (next) => {
+ expect(picker.state.open).to.be(true);
+ selector = TestUtils.scryRenderedDOMComponentsWithClass(picker.panelInstance,
+ 'rc-time-picker-panel-select')[2];
+ expect((input).value).to.be('12:00 AM');
+ const option = selector.getElementsByTagName('li')[1];
+ Simulate.click(option);
+ setTimeout(next, 200);
+ }, (next) => {
+ expect((input).value).to.be('12:00 PM');
+ next();
+ }, (next) => {
+ Simulate.click(selector.getElementsByTagName('li')[0]);
+ setTimeout(next, 200);
+ }, (next) => {
+ expect((input).value).to.be('12:00 AM');
+ next();
+ }], () => {
+ done();
+ });
+ });
+ });
});