Repository: gpbl/react-day-picker
Pull request #445 (2017-07-01 10:21:51)

Add support for handling mouse up and down on days
This PR adds the ability to add handlers for mouseUp and mouseDown events on days. This allows one to select dates by moving the mouse over the days while holding down the mouse button. 


Patch:
diff --git a/docs/docs/api-daypicker.md b/docs/docs/api-daypicker.md
index 00fe759f5..f1d092814 100644
--- a/docs/docs/api-daypicker.md
+++ b/docs/docs/api-daypicker.md
@@ -30,7 +30,7 @@ permalink: docs/api-daypicker.html
 
 #### Events
 
-[onBlur](#onblur), [onCaptionClick](#oncaptionclick), [onDayClick](#ondayclick), [onDayFocus](#ondayfocus), [onDayKeyDown](#ondaykeydown), [onDayMouseEnter](#ondaymouseenter), [onDayMouseLeave](#ondaymouseleave), [onDayTouchEnd](#ondaytouchend), [onDayTouchStart](#ondaytouchstart), [onFocus](#onfocus), [onKeyDown](#onkeydown), [onMonthChange](#onmonthchange)
+[onBlur](#onblur), [onCaptionClick](#oncaptionclick), [onDayClick](#ondayclick), [onDayFocus](#ondayfocus), [onDayKeyDown](#ondaykeydown), [onDayMouseEnter](#ondaymouseenter), [onDayMouseLeave](#ondaymouseleave), [onDayMouseDown](#ondaymousedown), [onDayMouseUp](#ondaymouseup), [onDayTouchEnd](#ondaytouchend), [onDayTouchStart](#ondaytouchstart), [onFocus](#onfocus), [onKeyDown](#onkeydown), [onMonthChange](#onmonthchange)
 
 #### Methods
 
@@ -372,6 +372,18 @@ Event handler when the mouse enters a day cell.
 
 Event handler when the mouse leave a day cell.
 
+### onDayMouseDown
+
+| **Type**: `(day: date, modifiers: Object, e: SyntheticEvent) ⇒  |void`
+
+Event handler when the mouse button is pressed on a day cell.
+
+### onDayMouseUp
+
+| **Type**: `(day: date, modifiers: Object, e: SyntheticEvent) ⇒  |void`
+
+Event handler when the mouse button is released on a day cell.
+
 ### onDayTouchStart
 
 | **Type**: `(day: date, modifiers: Object, e: SyntheticEvent) ⇒  |void`
diff --git a/src/Day.js b/src/Day.js
index 284022e15..953bf36d0 100644
--- a/src/Day.js
+++ b/src/Day.js
@@ -34,6 +34,8 @@ export default class Day extends Component {
     onKeyDown: PropTypes.func,
     onMouseEnter: PropTypes.func,
     onMouseLeave: PropTypes.func,
+    onMouseDown: PropTypes.func,
+    onMouseUp: PropTypes.func,
     onTouchEnd: PropTypes.func,
     onTouchStart: PropTypes.func,
     onFocus: PropTypes.func,
@@ -65,6 +67,8 @@ export default class Day extends Component {
       modifiers,
       onMouseEnter,
       onMouseLeave,
+      onMouseUp,
+      onMouseDown,
       onClick,
       onKeyDown,
       onTouchStart,
@@ -111,6 +115,8 @@ export default class Day extends Component {
         onKeyDown={handleEvent(onKeyDown, day, modifiers)}
         onMouseEnter={handleEvent(onMouseEnter, day, modifiers)}
         onMouseLeave={handleEvent(onMouseLeave, day, modifiers)}
+        onMouseUp={handleEvent(onMouseUp, day, modifiers)}
+        onMouseDown={handleEvent(onMouseDown, day, modifiers)}
         onTouchEnd={handleEvent(onTouchEnd, day, modifiers)}
         onTouchStart={handleEvent(onTouchStart, day, modifiers)}
         onFocus={handleEvent(onFocus, day, modifiers)}
diff --git a/src/DayPicker.js b/src/DayPicker.js
index b57bd72d9..0989065ca 100644
--- a/src/DayPicker.js
+++ b/src/DayPicker.js
@@ -105,6 +105,8 @@ export default class DayPicker extends Component {
     onDayKeyDown: PropTypes.func,
     onDayMouseEnter: PropTypes.func,
     onDayMouseLeave: PropTypes.func,
+    onDayMouseDown: PropTypes.func,
+    onDayMouseUp: PropTypes.func,
     onDayTouchStart: PropTypes.func,
     onDayTouchEnd: PropTypes.func,
     onDayFocus: PropTypes.func,
diff --git a/src/Month.js b/src/Month.js
index 3545fbab6..335fdf1b5 100644
--- a/src/Month.js
+++ b/src/Month.js
@@ -54,6 +54,8 @@ export default class Month extends Component {
     onDayKeyDown: PropTypes.func,
     onDayMouseEnter: PropTypes.func,
     onDayMouseLeave: PropTypes.func,
+    onDayMouseDown: PropTypes.func,
+    onDayMouseUp: PropTypes.func,
     onDayTouchEnd: PropTypes.func,
     onDayTouchStart: PropTypes.func,
     onWeekClick: PropTypes.func,
@@ -107,6 +109,8 @@ export default class Month extends Component {
         onKeyDown={this.props.onDayKeyDown}
         onMouseEnter={this.props.onDayMouseEnter}
         onMouseLeave={this.props.onDayMouseLeave}
+        onMouseDown={this.props.onDayMouseDown}
+        onMouseUp={this.props.onDayMouseUp}
         onTouchEnd={this.props.onDayTouchEnd}
         onTouchStart={this.props.onDayTouchStart}
       >
diff --git a/types/index.d.ts b/types/index.d.ts
index 44b011ffe..7b334835e 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -203,6 +203,16 @@ declare namespace DayPicker {
       modifiers: DayModifiers,
       e: React.MouseEvent<HTMLDivElement>
     ): void;
+    onDayMouseDown?(
+      day: Date,
+      modifiers: DayModifiers,
+      e: React.MouseEvent<HTMLDivElement>
+    ): void;
+    onDayMouseUp?(
+      day: Date,
+      modifiers: DayModifiers,
+      e: React.MouseEvent<HTMLDivElement>
+    ): void;
     onDayTouchEnd?(
       day: Date,
       modifiers: DayModifiers,


Test patch:
diff --git a/test/daypicker/events.js b/test/daypicker/events.js
index 4ada20aff..798324a0f 100644
--- a/test/daypicker/events.js
+++ b/test/daypicker/events.js
@@ -100,6 +100,42 @@ describe('DayPicker’s events handlers', () => {
     expect(arg1).toEqual({ foo: true });
     expect(arg2).toBeInstanceOf(SyntheticEvent);
   });
+  it('should call the `onDayMouseDown` event handler', () => {
+    const handleDayMouseDown = jest.fn();
+
+    const modifiers = { foo: d => d.getDate() === 15 };
+    const wrapper = mount(
+      <DayPicker modifiers={modifiers} onDayMouseDown={handleDayMouseDown} />
+    );
+
+    wrapper.find('.DayPicker-Day--foo').simulate('mouseDown');
+
+    const arg0 = handleDayMouseDown.mock.calls[0][0];
+    const arg1 = handleDayMouseDown.mock.calls[0][1];
+    const arg2 = handleDayMouseDown.mock.calls[0][2];
+    expect(arg0.getFullYear()).toEqual(new Date().getFullYear());
+    expect(arg0.getMonth()).toEqual(new Date().getMonth());
+    expect(arg1).toEqual({ foo: true });
+    expect(arg2).toBeInstanceOf(SyntheticEvent);
+  });
+  it('should call the `onDayMouseUp` event handler', () => {
+    const handleDayMouseUp = jest.fn();
+
+    const modifiers = { foo: d => d.getDate() === 15 };
+    const wrapper = mount(
+      <DayPicker modifiers={modifiers} onDayMouseUp={handleDayMouseUp} />
+    );
+
+    wrapper.find('.DayPicker-Day--foo').simulate('mouseUp');
+
+    const arg0 = handleDayMouseUp.mock.calls[0][0];
+    const arg1 = handleDayMouseUp.mock.calls[0][1];
+    const arg2 = handleDayMouseUp.mock.calls[0][2];
+    expect(arg0.getFullYear()).toEqual(new Date().getFullYear());
+    expect(arg0.getMonth()).toEqual(new Date().getMonth());
+    expect(arg1).toEqual({ foo: true });
+    expect(arg2).toBeInstanceOf(SyntheticEvent);
+  });
   it('should call the `onDayTouchStart` event handler', () => {
     const handleDayTouchStart = jest.fn();