diff --git a/components/date-picker/__tests__/date-picker.browser-test.jsx b/components/date-picker/__tests__/date-picker.browser-test.jsx
index a44c29c473..00ddbaaadb 100644
--- a/components/date-picker/__tests__/date-picker.browser-test.jsx
+++ b/components/date-picker/__tests__/date-picker.browser-test.jsx
@@ -431,6 +431,130 @@ describe('SLDSDatepicker', function describeFunction() {
input.simulate('change', { target: { value: '1/1/2020' } });
expect(wrapper.find('.slds-datepicker').length).to.equal(0);
});
+
+ it('typing partial date resets after pressing enter', function () {
+ const handleChangeSpy = sinon.spy();
+ wrapper = mount(
+
+ );
+
+ // Calendar is closed
+ expect(wrapper.find('.slds-datepicker').length).to.equal(0);
+
+ // Click on input to open the calendar
+ const trigger = wrapper.find(triggerClassSelector);
+ trigger.simulate('click', {});
+ expect(wrapper.find('.slds-datepicker').length).to.equal(1);
+
+ // Changing input value closes the calendar
+ const input = wrapper.find('input#sample-datepicker');
+
+ input.simulate('change', { target: { value: '' } });
+ input.simulate('click', {});
+ input.simulate('keyDown', { key: '9', keyCode: 49, which: 49 });
+ input.simulate('keyDown', { key: '/', keyCode: 191, which: 191 });
+ input.simulate('change', { target: { value: '9/' } });
+ expect(input.instance().value).to.equal('9/');
+ input.simulate('keyDown', {
+ key: 'Enter',
+ keyCode: KEYS.ENTER,
+ which: KEYS.ENTER,
+ });
+ expect(input.instance().value).to.equal('1/6/2007');
+ expect(handleChangeSpy.calledOnce).to.equal(true);
+ });
+
+ it('typing partial date resets after pressing escape', function () {
+ const handleChangeSpy = sinon.spy();
+ wrapper = mount(
+
+ );
+
+ // Calendar is closed
+ expect(wrapper.find('.slds-datepicker').length).to.equal(0);
+
+ // Click on input to open the calendar
+ const trigger = wrapper.find(triggerClassSelector);
+ trigger.simulate('click', {});
+ expect(wrapper.find('.slds-datepicker').length).to.equal(1);
+
+ // Changing input value closes the calendar
+ const input = wrapper.find('input#sample-datepicker');
+
+ input.simulate('change', { target: { value: '' } });
+ input.simulate('click', {});
+ input.simulate('keyDown', { key: '9', keyCode: 49, which: 49 });
+ input.simulate('keyDown', { key: '/', keyCode: 191, which: 191 });
+ input.simulate('change', { target: { value: '9/' } });
+ input.simulate('change', { target: { value: '9/' } });
+ expect(input.instance().value).to.equal('9/');
+ input.simulate('keyDown', {
+ key: 'Escape',
+ keyCode: KEYS.ESCAPE,
+ which: KEYS.ESCAPE,
+ });
+ expect(input.instance().value).to.equal('1/6/2007');
+ expect(handleChangeSpy.calledOnce).to.equal(false);
+ });
+
+ it('typing complete date resets after pressing escape', function () {
+ const handleChangeSpy = sinon.spy();
+ wrapper = mount(
+
+ );
+
+ // Calendar is closed
+ expect(wrapper.find('.slds-datepicker').length).to.equal(0);
+
+ // Click on input to open the calendar
+ const trigger = wrapper.find(triggerClassSelector);
+ trigger.simulate('click', {});
+ expect(wrapper.find('.slds-datepicker').length).to.equal(1);
+
+ // Changing input value closes the calendar
+ const input = wrapper.find('input#sample-datepicker');
+
+ input.simulate('change', { target: { value: '' } });
+ input.simulate('click', {});
+ input.simulate('change', { target: { value: '12/31/2007' } });
+ expect(input.instance().value).to.equal('12/31/2007');
+ input.simulate('keyDown', {
+ key: 'Escape',
+ keyCode: KEYS.ESCAPE,
+ which: KEYS.ESCAPE,
+ });
+ expect(input.instance().value).to.equal('1/6/2007');
+ expect(handleChangeSpy.calledOnce).to.equal(false);
+ });
+
+ it('typing complete date saves after pressing enter', function () {
+ const handleChangeSpy = sinon.spy();
+ wrapper = mount(
+
+ );
+
+ // Calendar is closed
+ expect(wrapper.find('.slds-datepicker').length).to.equal(0);
+
+ // Click on input to open the calendar
+ const trigger = wrapper.find(triggerClassSelector);
+ trigger.simulate('click', {});
+ expect(wrapper.find('.slds-datepicker').length).to.equal(1);
+
+ // Changing input value closes the calendar
+ const input = wrapper.find('input#sample-datepicker');
+
+ input.simulate('change', { target: { value: '' } });
+ input.simulate('click', {});
+ input.simulate('change', { target: { value: '12/31/2007' } });
+ expect(input.instance().value).to.equal('12/31/2007');
+ input.simulate('keyDown', {
+ key: 'Enter',
+ keyCode: KEYS.ENTER,
+ which: KEYS.ENTER,
+ });
+ expect(handleChangeSpy.calledOnce).to.equal(true);
+ });
});
});
diff --git a/components/date-picker/date-picker.jsx b/components/date-picker/date-picker.jsx
index ee8ee069e0..de9a68c341 100644
--- a/components/date-picker/date-picker.jsx
+++ b/components/date-picker/date-picker.jsx
@@ -260,17 +260,9 @@ const defaultProps = {
class Datepicker extends React.Component {
constructor(props) {
super(props);
- // Please remove `strValue` on the next breaking change.
- const formattedValue = props.formattedValue || props.strValue; // eslint-disable-line react/prop-types
- const dateString = props.formatter(props.value);
- const initDate = props.value ? dateString : formattedValue;
-
this.state = {
isOpen: false,
isOpenFromIcon: false,
- value: props.value,
- formattedValue: initDate || '',
- inputValue: initDate || '',
};
this.generatedId = shortid.generate();
@@ -279,6 +271,22 @@ class Datepicker extends React.Component {
checkProps(DATE_PICKER, props, componentDoc);
}
+ static getDerivedStateFromProps(props, state) {
+ if (props.value !== state.value) {
+ const formattedValue = props.formattedValue || props.strValue; // eslint-disable-line react/prop-types
+ const dateString = props.formatter(props.value);
+ const initDate = props.value ? dateString : formattedValue;
+ return {
+ isOpen: false,
+ isOpenFromIcon: false,
+ value: props.value,
+ formattedValue: initDate || '',
+ inputValue: initDate || '',
+ };
+ }
+ return state;
+ }
+
getDatePicker = ({ labels, assistiveText }) => {
let date;
// Use props if present. Otherwise, use state.
@@ -416,9 +424,7 @@ class Datepicker extends React.Component {
this.openDialog();
},
onKeyDown: this.handleKeyDown,
- value: this.props.value
- ? this.props.formatter(this.props.value)
- : this.state.inputValue,
+ value: this.state.inputValue,
};
// eslint-disable react/prop-types
@@ -512,16 +518,6 @@ class Datepicker extends React.Component {
formattedValue: event.target.value,
inputValue: event.target.value,
});
-
- const date = this.props.parser(event.target.value);
-
- if (this.props.onChange) {
- this.props.onChange(event, {
- date,
- formattedDate: event.target.value,
- timezoneOffset: date.getTimezoneOffset(),
- });
- }
};
handleKeyDown = (event) => {
@@ -535,9 +531,31 @@ class Datepicker extends React.Component {
this.setState({ isOpen: true });
}
- if (event.keyCode === KEYS.ESCAPE || event.keyCode === KEYS.ENTER) {
+ if (event.keyCode === KEYS.ESCAPE) {
EventUtil.trapEvent(event);
- this.setState({ isOpen: false });
+ this.setState(Datepicker.getDerivedStateFromProps(this.props, {}));
+ }
+
+ if (event.keyCode === KEYS.ENTER || event.keyCode === KEYS.TAB) {
+ const date = this.props.parser(event.target.value);
+ const formattedDate = this.props.formatter(date);
+ if (formattedDate !== 'Invalid date') {
+ this.setState({
+ value: date,
+ formattedValue: formattedDate,
+ inputValue: formattedDate,
+ isOpen: false,
+ });
+ if (this.props.onChange) {
+ this.props.onChange(event, {
+ date,
+ formattedDate,
+ timezoneOffset: date.getTimezoneOffset(),
+ });
+ }
+ } else {
+ this.setState(Datepicker.getDerivedStateFromProps(this.props, {}));
+ }
}
// Please remove `onKeyDown` on the next breaking change.
@@ -563,9 +581,10 @@ class Datepicker extends React.Component {
this.props.onRequestClose();
}
- if (this.getIsOpen()) {
- this.setState({ isOpen: false, isOpenFromIcon: false });
+ const wasOpen = this.getIsOpen();
+ this.setState(Datepicker.getDerivedStateFromProps(this.props, {}));
+ if (wasOpen) {
if (this.inputRef) {
this.inputRef.focus();
}