Skip to content

Commit

Permalink
add multi format support to DateInput (#437)
Browse files Browse the repository at this point in the history
  • Loading branch information
onlyann authored and zombieJ committed Nov 30, 2018
1 parent c92cf57 commit c99075d
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 12 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ lib
es
coverage
yarn.lock
.vscode
.vscode
package-lock.json
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,10 @@ http://react-component.github.io/calendar/examples/index.html
</tr>
<tr>
<td>format</td>
<td>String</td>
<td>String | String[]</td>
<td>depends on whether you set timePicker and your locale</td>
<td>use to format/parse date(without time) value to/from input</td>
<td>use to format/parse date(without time) value to/from input.
When an array is provided, all values are used for parsing and first value for display.</td>
</tr>
<tr>
<td>disabledDate</td>
Expand Down
46 changes: 43 additions & 3 deletions examples/antd-calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class Demo extends React.Component {
locale={cn ? zhCN : enUS}
style={{ zIndex: 1000 }}
dateInputPlaceholder="please input"
formatter={getFormat(state.showTime)}
format={getFormat(state.showTime)}
disabledTime={state.showTime ? disabledTime : null}
timePicker={state.showTime ? timePickerElement : null}
defaultValue={this.props.defaultCalendarValue}
Expand Down Expand Up @@ -158,7 +158,6 @@ class Demo extends React.Component {
>
<DatePicker
animation="slide-up"
disabled={state.disabled}
calendar={calendar}
value={state.value}
onChange={this.onChange}
Expand Down Expand Up @@ -186,6 +185,44 @@ class Demo extends React.Component {
}
}

const multiFormats = ['DD/MM/YYYY', 'DD/MM/YY', 'DDMMYY', 'D/M/YY'];

class DemoMultiFormat extends React.Component {
constructor(props) {
super(props);

this.state = {
value: now,
};
}

onChange = (value) => {
console.log('Calendar change: ', (value && value.format(format)));
this.setState({
value,
});
}

render() {
const state = this.state;
return (<div style={{ width: 400, margin: 20 }}>
<div style={{ marginBottom: 10 }}>
Accepts multiple input formats
<br/>
<small>{multiFormats.join(', ')}</small>
</div>
<Calendar
locale={cn ? zhCN : enUS}
style={{ zIndex: 1000 }}
dateInputPlaceholder="please input"
format={multiFormats}
value={state.value}
onChange={this.onChange}
/>
</div>);
}
}

function onStandaloneSelect(value) {
console.log('onStandaloneSelect');
console.log(value && value.format(format));
Expand Down Expand Up @@ -213,7 +250,7 @@ ReactDOM.render((<div
defaultValue={now}
disabledTime={disabledTime}
showToday
formatter={getFormat(true)}
format={getFormat(true)}
showOk={false}
timePicker={timePickerElement}
onChange={onStandaloneChange}
Expand All @@ -229,5 +266,8 @@ ReactDOM.render((<div
<Demo defaultCalendarValue={defaultCalendarValue} />
</div>
<div style={{ clear: 'both' }}></div>
<div>
<DemoMultiFormat />
</div>
</div>
</div>), document.getElementById('__react-content'));
29 changes: 23 additions & 6 deletions src/date/DateInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import ReactDOM from 'react-dom';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import moment from 'moment';
import { formatDate } from '../util';

const DateInput = createReactClass({
propTypes: {
prefixCls: PropTypes.string,
timePicker: PropTypes.object,
value: PropTypes.object,
disabledTime: PropTypes.any,
format: PropTypes.string,
format: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
locale: PropTypes.object,
disabledDate: PropTypes.func,
onChange: PropTypes.func,
Expand All @@ -24,8 +25,9 @@ const DateInput = createReactClass({
getInitialState() {
const selectedValue = this.props.selectedValue;
return {
str: selectedValue && selectedValue.format(this.props.format) || '',
str: formatDate(selectedValue, this.props.format),
invalid: false,
hasFocus: false,
};
},

Expand All @@ -34,10 +36,12 @@ const DateInput = createReactClass({
this.cachedSelectionEnd = this.dateInputInstance.selectionEnd;
// when popup show, click body will call this, bug!
const selectedValue = nextProps.selectedValue;
this.setState({
str: selectedValue && selectedValue.format(nextProps.format) || '',
invalid: false,
});
if (!this.state.hasFocus) {
this.setState({
str: formatDate(selectedValue, nextProps.format),
invalid: false,
});
}
},

componentDidUpdate() {
Expand Down Expand Up @@ -115,6 +119,17 @@ const DateInput = createReactClass({
this.dateInputInstance = dateInput;
},

onFocus() {
this.setState({ hasFocus: true });
},

onBlur() {
this.setState((prevState, prevProps) => ({
hasFocus: false,
str: formatDate(prevProps.value, prevProps.format),
}));
},

render() {
const props = this.props;
const { invalid, str } = this.state;
Expand All @@ -130,6 +145,8 @@ const DateInput = createReactClass({
disabled={props.disabled}
placeholder={placeholder}
onChange={this.onInputChange}
onFocus={this.onFocus}
onBlur={this.onBlur}
/>
</div>
{props.showClear ? (
Expand Down
12 changes: 12 additions & 0 deletions src/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,15 @@ export function isAllowedDate(value, disabledDate, disabledTime) {
}
return true;
}

export function formatDate(value, format) {
if (!value) {
return '';
}

if (Array.isArray(format)) {
format = format[0];
}

return value.format(format);
}
46 changes: 46 additions & 0 deletions tests/Calendar.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,52 @@ describe('Calendar', () => {
expect(onSelect.mock.calls[0][0].format(format)).toBe(expected);
expect(onChange.mock.calls[0][0].format(format)).toBe(expected);
});

it('supports an array of formats when parsing and formats using the first format', () => {
const expected = '21/01/2017';
const value = '21/01/17';

const onSelect = jest.fn();
const onChange = jest.fn();

const calendar = mount(<Calendar
format={['DD/MM/YYYY', 'DD/MM/YY']}
showToday
onSelect={onSelect}
onChange={onChange}
/>);
const input = calendar.find('.rc-calendar-input').hostNodes().at(0);
input.simulate('change', { target: { value } });

expect(onSelect.mock.calls[0][0].format('DD/MM/YYYY')).toBe(expected);
expect(onChange.mock.calls[0][0].format('DD/MM/YYYY')).toBe(expected);
});

it('only reformat the date when the input loses focus', () => {
const value = '21/01/17';

const onSelect = jest.fn();
const onChange = jest.fn();

const calendar = mount(<Calendar
format={['DD/MM/YYYY', 'DD/MM/YY']}
showToday
onSelect={onSelect}
onChange={onChange}
/>);

const input = calendar.find('.rc-calendar-input').hostNodes().at(0);
input.simulate('focus');
input.simulate('change', { target: { value } });

let inputValue = calendar.find('.rc-calendar-input').props().value;
expect(inputValue).toBe('21/01/17');

input.simulate('blur');

inputValue = calendar.find('.rc-calendar-input').props().value;
expect(inputValue).toBe('21/01/2017');
});
});

it('handle clear', () => {
Expand Down

0 comments on commit c99075d

Please sign in to comment.