Skip to content

Commit

Permalink
feature: 🔨 Add ARIA accessibility for shift+pageUp and shift+pageDown…
Browse files Browse the repository at this point in the history
… key

Add shift+pageUp and shift+pageDown handlers aligned with W3C WAI-ARIA principles.  Previously navigation moves to the previous month and the next month instead of moving to one year before and after.  After this change, it's moving to [the previous and the next year](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/examples/datepicker-dialog/)

Closes Hacker0x01#4456
  • Loading branch information
Balaji Sridharan committed Jan 16, 2024
1 parent 3d8e0cb commit c62fc43
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 16 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ The examples are hosted within the docs folder and are ran in the simple app tha
- _Up_: Move to the previous week.
- _Down_: Move to the next week.
- _PgUp_: Move to the previous month.
- _Shift+PgUp_: Move to the same day and month of the previous year. If that day does not exist, moves focus to the last day of the month.
- _PgDn_: Move to the next month.
- _Shift+PgDn_: Move to the same day and month of the next year. If that day does not exist, moves focus to the last day of the month.
- _Home_: Move to the first day (e.g Sunday) of the current week.
- _End_: Move to the last day (e.g. Saturday) of the current week.
- _Enter/Esc/Tab_: close the calendar. (Enter & Esc calls preventDefault)
Expand Down
39 changes: 23 additions & 16 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import {
subDays,
subMonths,
subWeeks,
addYears,
subYears,
isDayDisabled,
isDayInRange,
getEffectiveMinDate,
Expand Down Expand Up @@ -363,10 +365,10 @@ export default class DatePicker extends React.Component {
this.props.openToDate
? this.props.openToDate
: this.props.selectsEnd && this.props.startDate
? this.props.startDate
: this.props.selectsStart && this.props.endDate
? this.props.endDate
: newDate();
? this.props.startDate
: this.props.selectsStart && this.props.endDate
? this.props.endDate
: newDate();

// Convert the date from string format to standard Date format
modifyHolidays = () =>
Expand All @@ -387,8 +389,8 @@ export default class DatePicker extends React.Component {
minDate && isBefore(defaultPreSelection, startOfDay(minDate))
? minDate
: maxDate && isAfter(defaultPreSelection, endOfDay(maxDate))
? maxDate
: defaultPreSelection;
? maxDate
: defaultPreSelection;
return {
open: this.props.startOpen || false,
preventFocus: false,
Expand Down Expand Up @@ -843,6 +845,7 @@ export default class DatePicker extends React.Component {
onDayKeyDown = (event) => {
this.props.onKeyDown(event);
const eventKey = event.key;
const isShiftKeyActive = event.shiftKey;

const copy = newDate(this.state.preSelection);
if (eventKey === "Enter") {
Expand Down Expand Up @@ -880,10 +883,14 @@ export default class DatePicker extends React.Component {
newSelection = addWeeks(copy, 1);
break;
case "PageUp":
newSelection = subMonths(copy, 1);
newSelection = isShiftKeyActive
? subYears(copy, 1)
: subMonths(copy, 1);
break;
case "PageDown":
newSelection = addMonths(copy, 1);
newSelection = isShiftKeyActive
? addYears(copy, 1)
: addMonths(copy, 1);
break;
case "Home":
newSelection = getStartOfWeek(
Expand Down Expand Up @@ -1187,14 +1194,14 @@ export default class DatePicker extends React.Component {
typeof this.props.value === "string"
? this.props.value
: typeof this.state.inputValue === "string"
? this.state.inputValue
: this.props.selectsRange
? safeDateRangeFormat(
this.props.startDate,
this.props.endDate,
this.props,
)
: safeDateFormat(this.props.selected, this.props);
? this.state.inputValue
: this.props.selectsRange
? safeDateRangeFormat(
this.props.startDate,
this.props.endDate,
this.props,
)
: safeDateFormat(this.props.selected, this.props);

return React.cloneElement(customInput, {
[customInputRef]: (input) => {
Expand Down
30 changes: 30 additions & 0 deletions test/datepicker_test.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,21 @@ describe("DatePicker", () => {
utils.formatDate(data.datePicker.state.preSelection, data.testFormat),
).toBe(utils.formatDate(data.copyM, data.testFormat));
});
it("should handle onDayKeyDown Shift+PageUp", () => {
const data = getOnInputKeyDownStuff();

TestUtils.Simulate.keyDown(data.nodeInput, getKey("ArrowDown"));
TestUtils.Simulate.keyDown(
getSelectedDayNode(data.datePicker),
getKey("PageUp", true),
);

data.copyM = utils.subYears(data.copyM, 1);

expect(
utils.formatDate(data.datePicker.state.preSelection, data.testFormat),
).toBe(utils.formatDate(data.copyM, data.testFormat));
});
it("should handle onDayKeyDown PageDown", () => {
var data = getOnInputKeyDownStuff();
TestUtils.Simulate.keyDown(data.nodeInput, getKey("ArrowDown"));
Expand All @@ -943,6 +958,21 @@ describe("DatePicker", () => {
utils.formatDate(data.datePicker.state.preSelection, data.testFormat),
).toBe(utils.formatDate(data.copyM, data.testFormat));
});
it("should handle onDayKeyDown Shift+PageDown", () => {
const data = getOnInputKeyDownStuff();

TestUtils.Simulate.keyDown(data.nodeInput, getKey("ArrowDown"));
TestUtils.Simulate.keyDown(
getSelectedDayNode(data.datePicker),
getKey("PageDown", true),
);

data.copyM = utils.addYears(data.copyM, 1);

expect(
utils.formatDate(data.datePicker.state.preSelection, data.testFormat),
).toBe(utils.formatDate(data.copyM, data.testFormat));
});
it("should handle onDayKeyDown End", () => {
const data = getOnInputKeyDownStuff();
TestUtils.Simulate.keyDown(data.nodeInput, getKey("ArrowDown"));
Expand Down

0 comments on commit c62fc43

Please sign in to comment.