Repository: gpbl/react-day-picker
Pull request #531 (2017-10-26 19:27:19)

Don't overrides DayPickerInput selectedDays prop
This PR for #521. `dayPickerProps` moved after `selectedDays` so DayPickerInput's `selectedDays` won't be overridden.

gpbl: Thanks for the PR! Wondering why tests are failing here 🤔 
hydrognomik: It's because DayPickerInput has `HIDE_TIMEOUT`, but test checks `--selected` modifier immediately. Should I add `setTimeout` [here](https://github.com/gpbl/react-day-picker/blob/master/test/daypickerinput/events.js#L263)?
jm-maniego: I suggest supporting the old version, and just override it when it's passed

something like this maybe..
```javascript
var selectedDay = this.props.dayPickerProps.selectedDays;
if (!selectedDay && this.state.value) {
      const m = moment(this.state.value, this.props.format, true);
      if (m.isValid()) {
        selectedDay = m.toDate();
      }
    }
```
codecov[bot]: # [Codecov](https://codecov.io/gh/gpbl/react-day-picker/pull/531?src=pr&el=h1) Report
> Merging [#531](https://codecov.io/gh/gpbl/react-day-picker/pull/531?src=pr&el=desc) into [master](https://codecov.io/gh/gpbl/react-day-picker/commit/90040fc31a8854a5c0f3e9cc8b1d09cdd4cb64a6?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/gpbl/react-day-picker/pull/531/graphs/tree.svg?width=650&src=pr&token=1S9igPKpZd&height=150)](https://codecov.io/gh/gpbl/react-day-picker/pull/531?src=pr&el=tree)

```diff
@@          Coverage Diff          @@
##           master   #531   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files          15     15           
  Lines         541    546    +5     
  Branches      113    116    +3     
=====================================
+ Hits          541    546    +5
```


| [Impacted Files](https://codecov.io/gh/gpbl/react-day-picker/pull/531?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/DayPickerInput.js](https://codecov.io/gh/gpbl/react-day-picker/pull/531?src=pr&el=tree#diff-c3JjL0RheVBpY2tlcklucHV0Lmpz) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/gpbl/react-day-picker/pull/531?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/gpbl/react-day-picker/pull/531?src=pr&el=footer). Last update [90040fc...02c607e](https://codecov.io/gh/gpbl/react-day-picker/pull/531?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/src/DayPickerInput.js b/src/DayPickerInput.js
index 25bd9754e..299d16a8d 100644
--- a/src/DayPickerInput.js
+++ b/src/DayPickerInput.js
@@ -10,22 +10,21 @@ import { ESC } from './keys';
 export const HIDE_TIMEOUT = 100;
 
 function getStateFromProps(props) {
+  const { dayPickerProps, format, value } = props;
   let month;
-  if (props.value) {
-    const m = moment(props.value, props.format, true);
+  if (value) {
+    const m = moment(value, format, true);
     if (m.isValid()) {
       month = m.toDate();
     }
   } else {
-    month =
-      props.dayPickerProps.initialMonth ||
-      props.dayPickerProps.month ||
-      new Date();
+    month = dayPickerProps.initialMonth || dayPickerProps.month || new Date();
   }
 
   return {
-    value: props.value,
+    value,
     month,
+    selectedDays: dayPickerProps.selectedDays,
   };
 }
 
@@ -255,7 +254,15 @@ export default class DayPickerInput extends React.Component {
     }
     if (modifiers.selected && this.props.clickUnselectsDay) {
       // Unselect the day
-      this.setState({ value: '' }, this.hideAfterDayClick);
+      let { selectedDays } = this.state;
+      if (Array.isArray(selectedDays)) {
+        selectedDays = selectedDays.slice(0);
+        const selectedDayIdx = selectedDays.indexOf(day);
+        selectedDays.splice(selectedDayIdx, 1);
+      } else if (moment(selectedDays).isValid()) {
+        selectedDays = null;
+      }
+      this.setState({ value: '', selectedDays }, this.hideAfterDayClick);
       if (this.props.onDayChange) {
         this.props.onDayChange(undefined, modifiers);
       }
@@ -279,12 +286,16 @@ export default class DayPickerInput extends React.Component {
   };
 
   renderOverlay() {
+    const { format } = this.props;
+    const { selectedDays, value } = this.state;
     let selectedDay;
-    if (this.state.value) {
-      const m = moment(this.state.value, this.props.format, true);
+    if (!selectedDays && value) {
+      const m = moment(value, format, true);
       if (m.isValid()) {
         selectedDay = m.toDate();
       }
+    } else if (selectedDays) {
+      selectedDay = selectedDays;
     }
 
     return (
diff --git a/types/index.d.ts b/types/index.d.ts
index e4cf551f6..fa1c70e76 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -3,4 +3,4 @@
 import { DayPicker } from "./DayPicker";
 // We need to use 'export =' to be compatible with the 'module.exports = DayPicker.default || DayPicker' syntax
 // in DayPicker.js in the final NPM package.
-export = DayPicker;
+export default DayPicker;


Test patch:
diff --git a/test/daypickerinput/events.js b/test/daypickerinput/events.js
index 79e1f3ded..4dc0ab926 100644
--- a/test/daypickerinput/events.js
+++ b/test/daypickerinput/events.js
@@ -265,6 +265,26 @@ describe('DayPickerInput', () => {
         expect(wrapper.find('input')).toHaveProp('value', '');
         expect(wrapper.find('.DayPicker-Day--selected')).toHaveLength(0);
       });
+      it('should unselect the clicked day if already selected', () => {
+        const wrapper = mount(
+          <DayPickerInput
+            value="02/08/2017"
+            clickUnselectsDay
+            dayPickerProps={{
+              month: new Date(2017, 1),
+              selectedDays: [new Date(2017, 1, 8), new Date(2017, 1, 9)],
+            }}
+          />
+        );
+        wrapper.instance().showDayPicker();
+        wrapper.update();
+        wrapper
+          .find('.DayPicker-Day')
+          .at(10)
+          .simulate('click');
+        expect(wrapper.find('input')).toHaveProp('value', '');
+        expect(wrapper.find('.DayPicker-Day--selected')).toHaveLength(1);
+      });
       it('should call `onDayChange` when clicking a selected day', () => {
         const onDayChange = jest.fn();
         const wrapper = mount(
@@ -310,6 +330,45 @@ describe('DayPickerInput', () => {
           .simulate('click');
         expect(onDayChange).not.toHaveBeenCalled();
       });
+      it('should use `dayPickerProps.selectedDays` after clicking a day', () => {
+        const wrapper = mount(
+          <DayPickerInput
+            dayPickerProps={{
+              month: new Date(2017, 1),
+              selectedDays: [new Date(2017, 1, 8), new Date(2017, 1, 9)],
+            }}
+          />
+        );
+        wrapper.instance().showDayPicker();
+        wrapper.update();
+        wrapper
+          .find('.DayPicker-Day')
+          .at(9)
+          .simulate('click');
+        const selectedDays = wrapper.find('.DayPicker-Day--selected');
+        expect(selectedDays).toHaveLength(2);
+        expect(selectedDays.at(0)).toHaveText('8');
+        expect(selectedDays.at(1)).toHaveText('9');
+      });
+      it('should use `dayPickerProps.selectedDays` after typing a valid day', () => {
+        const wrapper = mount(
+          <DayPickerInput
+            dayPickerProps={{
+              month: new Date(2017, 1),
+              selectedDays: [new Date(2017, 1, 8), new Date(2017, 1, 9)],
+            }}
+          />
+        );
+        wrapper.instance().showDayPicker();
+        wrapper.update();
+        wrapper
+          .find('input')
+          .simulate('change', { target: { value: '02/07/2017' } });
+        const selectedDays = wrapper.find('.DayPicker-Day--selected');
+        expect(selectedDays).toHaveLength(2);
+        expect(selectedDays.at(0)).toHaveText('8');
+        expect(selectedDays.at(1)).toHaveText('9');
+      });
     });
   });
 });