Skip to content

Commit

Permalink
✨ Added support for up and down arrow key movement in the year picker…
Browse files Browse the repository at this point in the history
… of the date picker

- Prevent the default scroll movement when the arrow key is pressed

Closes #4446
  • Loading branch information
Balaji Sridharan committed Apr 16, 2024
1 parent 4500100 commit 01dbc14
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 5 deletions.
65 changes: 60 additions & 5 deletions src/year.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { getYear, newDate } from "./date_utils";
import * as utils from "./date_utils";
import { clsx } from "clsx";

const VERTICAL_NAVIGATION_OFFSET = 3;

export default class Year extends React.Component {
static propTypes = {
clearSelectingDate: PropTypes.func,
Expand Down Expand Up @@ -77,10 +79,12 @@ export default class Year extends React.Component {
if (this.isDisabled(newDate) || this.isExcluded(newDate)) return;
this.props.setPreSelection(newDate);

if (newYear - startPeriod === -1) {
this.updateFocusOnPaginate(yearItemNumber - 1);
} else if (newYear - startPeriod === yearItemNumber) {
this.updateFocusOnPaginate(0);
if (newYear - startPeriod < 0) {
this.updateFocusOnPaginate(yearItemNumber - (startPeriod - newYear));
} else if (newYear - startPeriod >= yearItemNumber) {
this.updateFocusOnPaginate(
Math.abs(yearItemNumber - (newYear - startPeriod)),
);
} else this.YEAR_REFS[newYear - startPeriod].current.focus();
};

Expand Down Expand Up @@ -168,7 +172,12 @@ export default class Year extends React.Component {

onYearKeyDown = (e, y) => {
const { key } = e;
const { handleOnKeyDown } = this.props;
const { date, yearItemNumber, handleOnKeyDown } = this.props;

if (key !== "Tab") {
// preventDefault on tab event blocks focus change
e.preventDefault();
}

if (!this.props.disabledKeyboardNavigation) {
switch (key) {
Expand All @@ -188,6 +197,52 @@ export default class Year extends React.Component {
utils.subYears(this.props.preSelection, 1),
);
break;
case "ArrowUp": {
const { startPeriod } = utils.getYearsPeriod(date, yearItemNumber);
let offset = VERTICAL_NAVIGATION_OFFSET;
let newYear = y - offset;

if (newYear < startPeriod) {
const leftOverOffset = yearItemNumber % offset;

if (y >= startPeriod && y < startPeriod + leftOverOffset) {
offset = leftOverOffset;
} else {
offset += leftOverOffset;
}

newYear = y - offset;
}

this.handleYearNavigation(
newYear,
utils.subYears(this.props.preSelection, offset),
);
break;
}
case "ArrowDown": {
const { endPeriod } = utils.getYearsPeriod(date, yearItemNumber);
let offset = VERTICAL_NAVIGATION_OFFSET;
let newYear = y + offset;

if (newYear > endPeriod) {
const leftOverOffset = yearItemNumber % offset;

if (y <= endPeriod && y > endPeriod - leftOverOffset) {
offset = leftOverOffset;
} else {
offset += leftOverOffset;
}

newYear = y + offset;
}

this.handleYearNavigation(
newYear,
utils.addYears(this.props.preSelection, offset),
);
break;
}
}
}

Expand Down
94 changes: 94 additions & 0 deletions test/year_picker_test.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,20 @@ describe("YearPicker", () => {
which: 39,
});

const simulateUp = (target) =>
fireEvent.keyDown(target, {
key: "ArrowUp",
keyCode: 38,
which: 38,
});

const simulateDown = (target) =>
fireEvent.keyDown(target, {
key: "ArrowDown",
keyCode: 40,
which: 40,
});

it("should preSelect and set 2020 on left arrow press", () => {
const yearPicker = getPicker("2021-01-01");

Expand All @@ -657,6 +671,86 @@ describe("YearPicker", () => {

expect(utils.getYear(preSelected)).toBe(2022);
});
it("should preSelect and set 2021 on up arrow press", () => {
const yearPicker = getPicker("2024-01-01");

const target = yearPicker.querySelector(
".react-datepicker__year-text--selected",
);
simulateUp(target);

expect(utils.getYear(preSelected)).toBe(2021);
});
it("should preSelect and set 2027 on down arrow press", () => {
const yearPicker = getPicker("2024-01-01");

const target = yearPicker.querySelector(
".react-datepicker__year-text--selected",
);
simulateDown(target);

expect(utils.getYear(preSelected)).toBe(2027);
});
it("should paginate from 2018 to 2015", () => {
const yearPicker = getPicker("2018-01-01");

const target = yearPicker.querySelector(
".react-datepicker__year-text--selected",
);
simulateUp(target);

expect(utils.getYear(preSelected)).toBe(2015);
});
it("should paginate from 2018 to 2016 with custom yearItemNumber", () => {
const yearPicker = getPicker("2018-01-01", { yearItemNumber: 8 });

const target = yearPicker.querySelector(
".react-datepicker__year-text--selected",
);
simulateUp(target);

expect(utils.getYear(preSelected)).toBe(2016);
});
it("should paginate from 2019 to 2014 with custom yearItemNumber", () => {
const yearPicker = getPicker("2019-01-01", { yearItemNumber: 8 });

const target = yearPicker.querySelector(
".react-datepicker__year-text--selected",
);
simulateUp(target);

expect(utils.getYear(preSelected)).toBe(2014);
});
it("should paginate from 2028 to 2031", () => {
const yearPicker = getPicker("2028-01-01");

const target = yearPicker.querySelector(
".react-datepicker__year-text--selected",
);
simulateDown(target);

expect(utils.getYear(preSelected)).toBe(2031);
});
it("should paginate from 2024 to 2026 with custom yearItemNumber", () => {
const yearPicker = getPicker("2024-01-01", { yearItemNumber: 8 });

const target = yearPicker.querySelector(
".react-datepicker__year-text--selected",
);
simulateDown(target);

expect(utils.getYear(preSelected)).toBe(2026);
});
it("should paginate from 2022 to 2027 with custom yearItemNumber", () => {
const yearPicker = getPicker("2022-01-01", { yearItemNumber: 8 });

const target = yearPicker.querySelector(
".react-datepicker__year-text--selected",
);
simulateDown(target);

expect(utils.getYear(preSelected)).toBe(2027);
});
it("should paginate from 2017 to 2016", () => {
const yearPicker = getPicker("2017-01-01");

Expand Down

0 comments on commit 01dbc14

Please sign in to comment.