Skip to content

Commit

Permalink
Keyboard accessibility improvement #245 #260 #290
Browse files Browse the repository at this point in the history
  • Loading branch information
shahabyazdi committed May 15, 2024
1 parent 929e617 commit c6c0fe7
Show file tree
Hide file tree
Showing 17 changed files with 257 additions and 122 deletions.
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -621,28 +621,34 @@ export default function Example() {
</tr>
<tr>
<td>mobileButtons</td>
<td style="text-align:center"> HTMLButtonElement[]</td>
<td style="text-align:center">HTMLButtonElement[]</td>
<td style="text-align:center">[]</td>
<td>DatePicker</td>
</tr>
<tr>
<td>dateSeparator</td>
<td style="text-align:center"> string</td>
<td style="text-align:center">String</td>
<td style="text-align:center">'~' in range mode, ',' in multiple mode</td>
<td>DatePicker</td>
</tr>
<tr>
<td>multipleRangeSeparator</td>
<td style="text-align:center"> string</td>
<td style="text-align:center">String</td>
<td style="text-align:center">','</td>
<td>DatePicker</td>
</tr>
<tr>
<tr>
<td>typingTimeout</td>
<td style="text-align:center"> string</td>
<td style="text-align:center">String</td>
<td style="text-align:center">700</td>
<td>DatePicker</td>
</tr>
<tr>
<td>autoFocus</td>
<td style="text-align:center">Boolean</td>
<td style="text-align:center">false</td>
<td>Calendar</td>
</tr>
</tbody>
</table>

Expand Down
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 4.5.0

- Keyboard accessibility improvement [#290](https://github.com/shahabyazdi/react-multi-date-picker/issues/290), [#245](https://github.com/shahabyazdi/react-multi-date-picker/issues/245), [#260](https://github.com/shahabyazdi/react-multi-date-picker/issues/260)

# 4.4.2

- Added isOpen type to DatePickerRef [#246](https://github.com/shahabyazdi/react-multi-date-picker/issues/246)
Expand Down
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ declare module "react-multi-date-picker" {
formatYear?: (year: string, month: string) => string;
highlightToday?: boolean;
headerOrder?: Array<HeaderItem>;
autoFocus?: boolean;
}

export interface DatePickerProps {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-multi-date-picker",
"version": "4.4.2",
"version": "4.5.0",
"description": "A simple React datepicker component for working with gregorian, persian, arabic and indian calendars with the ability to select the date by single, multiple, range and multiple range pickers.",
"main": "./build/index.js",
"types": "index.d.ts",
Expand Down
3 changes: 2 additions & 1 deletion src/components/arrow/arrow.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React from "react";

export default function Arrow({ direction, onClick, disabled }) {
export default function Arrow({ direction, onClick, disabled, onKeyDown }) {
return (
<button
type="button"
className={`rmdp-arrow-container ${direction} ${
disabled ? "disabled" : ""
}`}
onClick={onClick}
onKeyDown={onKeyDown}
aria-roledescription={`button to navigate ${direction.replace(
"rmdp-",
""
Expand Down
12 changes: 12 additions & 0 deletions src/components/calendar/calendar.css
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@
color: black;
}

.rmdp-calendar *:focus {
outline-color: #00539c;
}

.rmdp-day:not(.rmdp-range):focus {
border-radius: 50%;
}

.rmdp-ym .rmdp-day:not(.rmdp-range):focus {
border-radius: 15px;
}

.rmdp-week-day {
cursor: default;
color: var(--rmdp-primary);
Expand Down
10 changes: 10 additions & 0 deletions src/components/calendar/calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import isArray from "../../shared/isArray";
import check from "../../shared/check";
import toLocaleDigits from "../../shared/toLocaleDigits";
import isRTL from "../../shared/isRTL";
import { findFocusable } from "../../shared/handleFocus";
import "./calendar.css";

function Calendar(
Expand Down Expand Up @@ -75,6 +76,7 @@ function Calendar(
highlightToday = true,
headerOrder = ["LEFT_BUTTON", "MONTH_YEAR", "RIGHT_BUTTON"],
style = {},
autoFocus = false,
},
outerRef
) {
Expand Down Expand Up @@ -302,6 +304,14 @@ function Calendar(
},
{ datePickerProps, DatePicker, ...calendarProps } = arguments[0];

useEffect(() => {
const { Calendar } = ref.current;

if (!Calendar) return;

findFocusable(Calendar, undefined, autoFocus && !DatePicker);
}, [autoFocus, state.today, DatePicker]);

initPlugins();

return state.today ? (
Expand Down
70 changes: 12 additions & 58 deletions src/components/day_picker/day_picker.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import React, { useMemo, useRef } from "react";
import React, { useMemo, useRef, useState } from "react";
import DateObject from "react-date-object";
import WeekDays from "../week_days/week_days";
import selectDate from "../../shared/selectDate";
import isSameDate from "../../shared/isSameDate";
import getRangeClass from "../../shared/getRangeClass";
import getRangeHoverClass from "../../shared/getRangeHoverClass";
import { useState } from "react";
import handleFocus from "../../shared/handleFocus";

const ariaLabelFormat = "dddd MMMM DD of YYYY";

let timeout;

export default function DayPicker({
state,
setState,
onChange,
showOtherDays = false,
mapDays,
Expand Down Expand Up @@ -44,11 +41,11 @@ export default function DayPicker({
selectedDate,
onlyMonthPicker,
onlyYearPicker,
mustShowMonthPicker,
mustShowYearPicker,
} = state,
mustShowDayPicker = !onlyMonthPicker && !onlyYearPicker,
[dateHovered, setDateHovered] = useState(),
isDateSelected =
multiple || range ? selectedDate?.length > 0 : !!selectedDate;
[dateHovered, setDateHovered] = useState();

ref.current.date = date;

Expand Down Expand Up @@ -80,6 +77,9 @@ export default function DayPicker({
className={`rmdp-day-picker ${fullYear ? "rmdp-full-year" : ""}`}
style={{ display: fullYear ? "grid" : "flex" }}
onMouseLeave={() => rangeHover && setDateHovered()}
data-active={
mustShowDayPicker && !mustShowMonthPicker && !mustShowYearPicker
}
>
{months.map((weeks, monthIndex) => (
<div
Expand Down Expand Up @@ -134,23 +134,20 @@ export default function DayPicker({
className = className.replace("sd", "");
}

const hasTabIndex = isDateSelected
? parentClassName.includes("selected") ||
parentClassName.includes("range")
: parentClassName.includes("today");

return (
<div
key={i}
tabIndex={hasTabIndex ? 0 : -1}
tabIndex={-1}
aria-label={`Choose ${object.date.format(
ariaLabelFormat
)}`}
className={parentClassName}
onMouseEnter={() =>
rangeHover && setDateHovered(object.date)
}
onKeyDown={(e) => handleKeyDown(e, object)}
onKeyDown={(e) =>
handleFocus(e, object, { format: ariaLabelFormat })
}
onClick={() => {
if (!mustDisplayDay(object) || object.disabled) {
return;
Expand Down Expand Up @@ -304,49 +301,6 @@ export default function DayPicker({

return allProps;
}

function handleKeyDown(e, object) {
const { currentTarget, key, code } = e;
const numbers = { ArrowRight: 1, ArrowLeft: -1, ArrowUp: -7, ArrowDown: 7 };

if (code === "Space" || key === " ") {
e.preventDefault();
currentTarget.click();
} else if (Object.keys(numbers).includes(key)) {
e.preventDefault();

const number = numbers[key];
const date = new DateObject(object.date).add(number, "day");
const div = getNode(date);

focus(div);

function focus(node) {
if (!node) return next();

const classes = node.getAttribute("class");

if (!classes.includes("hidden") && !classes.includes("disabled")) {
node.focus();
} else {
next();
}
}

function next() {
setState({ ...state, date });
clearTimeout(timeout);

timeout = setTimeout(() => focus(getNode(date)), 100);
}
}
}

function getNode(date) {
return divRef.current.querySelector(
`[aria-label*='${date.format(ariaLabelFormat)}']`
);
}
}

function getMonths(date, showOtherDays, numberOfMonths, weekStartDayIndex) {
Expand Down
Loading

0 comments on commit c6c0fe7

Please sign in to comment.