Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mulit format support to TimePicker #133

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
Empty file added examples/multiFormat.html
Empty file.
22 changes: 22 additions & 0 deletions examples/multiFormat.js
Original file line number Diff line number Diff line change
@@ -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(
<TimePicker
defaultValue={now}
format={format}
/>,
document.getElementById('__react-content')
);
76 changes: 38 additions & 38 deletions rc-time-picker.d.ts
Original file line number Diff line number Diff line change
@@ -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<TimePickerProps> {}
}
8 changes: 5 additions & 3 deletions src/Combobox.jsx
Original file line number Diff line number Diff line change
@@ -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}`;
Expand All @@ -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,
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 4 additions & 3 deletions src/Header.jsx
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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,
};
}
Expand All @@ -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,
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/Panel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 3 additions & 2 deletions src/TimePicker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}

Expand All @@ -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,
Expand Down Expand Up @@ -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}
Expand Down
13 changes: 13 additions & 0 deletions src/util/index.js
Original file line number Diff line number Diff line change
@@ -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));
}
31 changes: 30 additions & 1 deletion tests/TimePicker.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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');
});
});
});