Skip to content

Commit

Permalink
feat : add usePointerEvent props
Browse files Browse the repository at this point in the history
  • Loading branch information
yuki0410-dev committed Mar 1, 2024
1 parent 5f20755 commit a42054a
Show file tree
Hide file tree
Showing 14 changed files with 129 additions and 13 deletions.
1 change: 1 addition & 0 deletions docs/datepicker.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,4 @@ General datepicker component.
| `icon` | `string` or `element` | | Allows using a custom calendar icon. Accepts a string (icon class name) or a React component (e.g., custom SVG). If a string is passed, an `<i>` element is rendered with that string as its class name. If a React component is passed, it is rendered as-is. |
| `calendarIconClassName` | `string` | | Accepts a string that will be added as an additional CSS class to the calendar icon, allowing further styling customization. |
| `showIcon` | `bool` | `true` | Determines whether the calendar icon is displayed. Set to `true` to display the icon, and `false` to hide it. If `icon` prop is also provided, the custom icon will be displayed when `showIcon` is `true`. |
| `usePointerEvent` | `bool` | false | True if Pointer Events (e.g, onPointerEnter, onPointerLeave) are used internally instead of Mouse Events (e.g, onMouseEnter, onMouseLeave). |
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,4 @@
| `wrapperClassName` | `string` | | |
| `yearDropdownItemNumber` | `number` | | |
| `yearItemNumber` | `number` | `DEFAULT_YEAR_ITEM_NUMBER` | |
| `usePointerEvent` | `bool` | `false` | |
1 change: 1 addition & 0 deletions docs/year.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@
| `setPreSelection` | `func` | | |
| `startDate` | `instanceOfDate` | | |
| `yearItemNumber` | `number` | | |
| `usePointerEvent` | `bool` | | |
2 changes: 2 additions & 0 deletions src/calendar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ export default class Calendar extends React.Component {
renderMonthContent: PropTypes.func,
renderQuarterContent: PropTypes.func,
renderYearContent: PropTypes.func,
usePointerEvent: PropTypes.bool,
onDayMouseEnter: PropTypes.func,
onMonthMouseLeave: PropTypes.func,
onYearMouseEnter: PropTypes.func,
Expand Down Expand Up @@ -897,6 +898,7 @@ export default class Calendar extends React.Component {
onDayClick={this.handleDayClick}
handleOnKeyDown={this.props.handleOnDayKeyDown}
handleOnMonthKeyDown={this.props.handleOnKeyDown}
usePointerEvent={this.props.usePointerEvent}
onDayMouseEnter={this.handleDayMouseEnter}
onMouseLeave={this.handleMonthMouseLeave}
onWeekSelect={this.props.onWeekSelect}
Expand Down
4 changes: 3 additions & 1 deletion src/day.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default class Day extends React.Component {
shouldFocusDayInline: PropTypes.bool,
month: PropTypes.number,
onClick: PropTypes.func,
usePointerEvent: PropTypes.bool,
onMouseEnter: PropTypes.func,
preSelection: PropTypes.instanceOf(Date),
selected: PropTypes.object,
Expand Down Expand Up @@ -434,7 +435,8 @@ export default class Day extends React.Component {
className={this.getClassNames(this.props.day)}
onKeyDown={this.handleOnKeyDown}
onClick={this.handleClick}
onMouseEnter={this.handleMouseEnter}
onMouseEnter={!this.props.usePointerEvent ? this.handleMouseEnter : undefined}
onPointerEnter={this.props.usePointerEvent ? this.handleMouseEnter : undefined}
tabIndex={this.getTabIndex()}
aria-label={this.getAriaLabel()}
role="option"
Expand Down
3 changes: 3 additions & 0 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export default class DatePicker extends React.Component {
customTimeInput: null,
calendarStartDay: undefined,
toggleCalendarOnIconClick: false,
usePointerEvent: false,
};
}

Expand Down Expand Up @@ -311,6 +312,7 @@ export default class DatePicker extends React.Component {
customTimeInput: PropTypes.element,
weekAriaLabelPrefix: PropTypes.string,
monthAriaLabelPrefix: PropTypes.string,
usePointerEvent: PropTypes.bool,
};

constructor(props) {
Expand Down Expand Up @@ -1139,6 +1141,7 @@ export default class DatePicker extends React.Component {
isInputFocused={this.state.focused}
customTimeInput={this.props.customTimeInput}
setPreSelection={this.setPreSelection}
usePointerEvent={this.props.usePointerEvent}
>
{this.props.children}
</WrappedCalendar>
Expand Down
11 changes: 8 additions & 3 deletions src/month.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export default class Month extends React.Component {
maxDate: PropTypes.instanceOf(Date),
minDate: PropTypes.instanceOf(Date),
onDayClick: PropTypes.func,
usePointerEvent: PropTypes.bool,
onDayMouseEnter: PropTypes.func,
onMouseLeave: PropTypes.func,
onWeekSelect: PropTypes.func,
Expand Down Expand Up @@ -311,6 +312,7 @@ export default class Month extends React.Component {
day={currentWeekStart}
month={utils.getMonth(this.props.day)}
onDayClick={this.handleDayClick}
usePointerEvent={this.props.usePointerEvent}
onDayMouseEnter={this.handleDayMouseEnter}
onWeekSelect={this.props.onWeekSelect}
formatWeekNumber={this.props.formatWeekNumber}
Expand Down Expand Up @@ -684,7 +686,8 @@ export default class Month extends React.Component {

this.onMonthKeyDown(ev, m);
}}
onMouseEnter={() => this.onMonthMouseEnter(m)}
onMouseEnter={!this.props.usePointerEvent ? () => this.onMonthMouseEnter(m) : undefined}
onPointerEnter={this.props.usePointerEvent ? () => this.onMonthMouseEnter(m) : undefined}
tabIndex={this.getTabIndex(m)}
className={this.getMonthClassNames(m)}
role="option"
Expand Down Expand Up @@ -715,7 +718,8 @@ export default class Month extends React.Component {
onKeyDown={(ev) => {
this.onQuarterKeyDown(ev, q);
}}
onMouseEnter={() => this.onQuarterMouseEnter(q)}
onMouseEnter={!this.props.usePointerEvent ? () => this.onQuarterMouseEnter(q) : undefined}
onPointerEnter={this.props.usePointerEvent ? () => this.onQuarterMouseEnter(q) : undefined}
className={this.getQuarterClassNames(q)}
aria-selected={this.isSelectedQuarter(day, q, selected)}
tabIndex={this.getQuarterTabIndex(q)}
Expand Down Expand Up @@ -760,7 +764,8 @@ export default class Month extends React.Component {
return (
<div
className={this.getClassNames()}
onMouseLeave={this.handleMouseLeave}
onMouseLeave={!this.props.usePointerEvent ? this.handleMouseLeave : undefined}
onPointerLeave={this.props.usePointerEvent ? this.handleMouseLeave : undefined}
aria-label={`${ariaLabelPrefix} ${utils.formatDate(day, "yyyy-MM")}`}
role="listbox"
>
Expand Down
2 changes: 2 additions & 0 deletions src/week.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default class Week extends React.Component {
minDate: PropTypes.instanceOf(Date),
month: PropTypes.number,
onDayClick: PropTypes.func,
usePointerEvent: PropTypes.bool,
onDayMouseEnter: PropTypes.func,
onWeekSelect: PropTypes.func,
preSelection: PropTypes.instanceOf(Date),
Expand Down Expand Up @@ -149,6 +150,7 @@ export default class Week extends React.Component {
day={day}
month={this.props.month}
onClick={this.handleDayClick.bind(this, day)}
usePointerEvent={this.props.usePointerEvent}
onMouseEnter={this.handleDayMouseEnter.bind(this, day)}
minDate={this.props.minDate}
maxDate={this.props.maxDate}
Expand Down
10 changes: 7 additions & 3 deletions src/year.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default class Year extends React.Component {
inline: PropTypes.bool,
maxDate: PropTypes.instanceOf(Date),
minDate: PropTypes.instanceOf(Date),
usePointerEvent: PropTypes.bool,
onYearMouseEnter: PropTypes.func.isRequired,
onYearMouseLeave: PropTypes.func.isRequired,
selectingDate: PropTypes.instanceOf(Date),
Expand Down Expand Up @@ -259,8 +260,10 @@ export default class Year extends React.Component {
}}
tabIndex={this.getYearTabIndex(y)}
className={this.getYearClassNames(y)}
onMouseEnter={(ev) => onYearMouseEnter(ev, y)}
onMouseLeave={(ev) => onYearMouseLeave(ev, y)}
onMouseEnter={!this.props.usePointerEvent ? (ev) => onYearMouseEnter(ev, y) : undefined}
onPointerEnter={this.props.usePointerEvent ? (ev) => onYearMouseEnter(ev, y) : undefined}
onMouseLeave={!this.props.usePointerEvent ? (ev) => onYearMouseLeave(ev, y) : undefined}
onPointerLeave={this.props.usePointerEvent ? (ev) => onYearMouseLeave(ev, y) : undefined}
key={y}
aria-current={this.isCurrentYear(y) ? "date" : undefined}
>
Expand All @@ -273,7 +276,8 @@ export default class Year extends React.Component {
<div className={this.getYearContainerClassNames()}>
<div
className="react-datepicker__year-wrapper"
onMouseLeave={this.props.clearSelectingDate}
onMouseLeave={!this.props.usePointerEvent ? this.props.clearSelectingDate : undefined}
onPointerLeave={this.props.usePointerEvent ? this.props.clearSelectingDate : undefined}
>
{yearsList}
</div>
Expand Down
21 changes: 20 additions & 1 deletion test/calendar_test.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ describe("Calendar", () => {
expect(weekLabel.at(0).text()).toBe("Foo");
});

it("should track the currently hovered day", () => {
it("should track the currently hovered day (Mouse Event)", () => {
const calendar = mount(
<Calendar
dateFormat={dateFormat}
Expand All @@ -876,6 +876,25 @@ describe("Calendar", () => {
);
});

it("should track the currently hovered day (Pointer Event)", () => {
const calendar = mount(
<Calendar
dateFormat={dateFormat}
dropdownMode="scroll"
onClickOutside={() => {}}
onSelect={() => {}}
usePointerEvent
/>,
);
const day = calendar.find(Day).first();
day.simulate("pointerenter");
const month = calendar.find(Month).first();
expect(month.prop("selectingDate")).toBeDefined();
expect(utils.isSameDay(month.prop("selectingDate"), day.prop("day"))).toBe(
true,
);
});

it("should clear the hovered day when the mouse leaves", () => {
const calendar = mount(
<Calendar
Expand Down
29 changes: 28 additions & 1 deletion test/datepicker_test.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2589,7 +2589,7 @@ describe("DatePicker", () => {
});

describe("Year picker", () => {
it("should call onYearMouseEnter and onYearMouseEnter", () => {
it("should call onYearMouseEnter and onYearMouseEnter (Mouse Event)", () => {
const onYearMouseEnterSpy = jest.fn();
const onYearMouseLeaveSpy = jest.fn();
const datePicker = mount(
Expand All @@ -2614,5 +2614,32 @@ describe("DatePicker", () => {
expect(onYearMouseEnterSpy).toHaveBeenCalled();
expect(onYearMouseLeaveSpy).toHaveBeenCalled();
});

it("should call onYearMouseEnter and onYearMouseEnter (Pointer Event)", () => {
const onYearMouseEnterSpy = jest.fn();
const onYearMouseLeaveSpy = jest.fn();
const datePicker = mount(
<DatePicker
selected={new Date(2023, 0, 1)}
showYearPicker
onYearMouseEnter={onYearMouseEnterSpy}
onYearMouseLeave={onYearMouseLeaveSpy}
usePointerEvent
/>,
);

const dateInputWrapper = datePicker.find("input");
dateInputWrapper.simulate("click");
const calendarWrapper = datePicker.find("Calendar");
const selectedYear = calendarWrapper.find(
".react-datepicker__year-text--selected",
);

selectedYear.simulate("pointerenter");
selectedYear.simulate("pointerleave");

expect(onYearMouseEnterSpy).toHaveBeenCalled();
expect(onYearMouseLeaveSpy).toHaveBeenCalled();
});
});
});
9 changes: 9 additions & 0 deletions test/day_test.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,15 @@ describe("Day", () => {
shallowDay.find(".react-datepicker__day").simulate("mouseenter");
expect(onMouseEnterCalled).toBe(true);
});

it("should call onPointerEnter if day is hovered", () => {
const shallowDay = renderDay(newDate(), {
onMouseEnter,
usePointerEvent: true,
});
shallowDay.find(".react-datepicker__day").simulate("pointerenter");
expect(onMouseEnterCalled).toBe(true);
});
});

describe("for a start date picker with selectsRange prop", () => {
Expand Down
21 changes: 20 additions & 1 deletion test/month_test.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ describe("Month", () => {
expect(mouseLeaveCalled).toBe(true);
});

it("should call the provided onDayMouseEnter function", () => {
it("should call the provided onDayMouseEnter (Mouse Event) function", () => {
let dayMouseEntered = null;

function onDayMouseEnter(day) {
Expand All @@ -145,6 +145,25 @@ describe("Month", () => {
expect(utils.isSameDay(day.prop("day"), dayMouseEntered)).toBe(true);
});

it("should call the provided onDayMouseEnter (Pointer Event) function", () => {
let dayMouseEntered = null;

function onDayMouseEnter(day) {
dayMouseEntered = day;
}

const month = mount(
<Month
day={utils.newDate()}
onDayMouseEnter={onDayMouseEnter}
usePointerEvent
/>,
);
const day = month.find(Day).first();
day.simulate("pointerenter");
expect(utils.isSameDay(day.prop("day"), dayMouseEntered)).toBe(true);
});

it("should use its month order in handleDayClick", () => {
const order = 2;
let orderValueMatched = false;
Expand Down
27 changes: 24 additions & 3 deletions test/week_test.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import Week from "../src/week";
import WeekNumber from "../src/week_number";
import Day from "../src/day";
import { shallow } from "enzyme";
import { shallow, mount } from "enzyme";
import * as utils from "../src/date_utils";

describe("Week", () => {
Expand Down Expand Up @@ -161,22 +161,43 @@ describe("Week", () => {
expect(weekNumberElement.prop("weekNumber")).toBe(9);
});

it("should call the provided onDayMouseEnter function", () => {
it("should call the provided onDayMouseEnter (Mouse Event) function", () => {
let dayMouseEntered = null;

function onDayMouseEnter(day) {
dayMouseEntered = day;
}

const weekStart = utils.newDate();
const week = shallow(
const week = mount(
<Week day={weekStart} onDayMouseEnter={onDayMouseEnter} />,
);
const day = week.find(Day).first();
day.simulate("mouseenter");
expect(day.prop("day")).toEqual(dayMouseEntered);
});

it("should call the provided onDayMouseEnter (Pointer Event) function", () => {
let dayMouseEntered = null;

function onDayMouseEnter(day) {
dayMouseEntered = day;
}

const weekStart = utils.newDate();
// NOTE: `shallow` cannot correctly perform `simulate("pointerenter")`, so `mount` is used
const week = mount(
<Week
day={weekStart}
onDayMouseEnter={onDayMouseEnter}
usePointerEvent
/>,
);
const day = week.find(Day).first();
day.simulate("pointerenter");
expect(day.prop("day")).toEqual(dayMouseEntered);
});

describe("handleWeekClick", () => {
it("should call onWeekSelect prop with correct arguments", () => {
const onWeekSelect = jest.fn();
Expand Down

0 comments on commit a42054a

Please sign in to comment.