Skip to content

Commit

Permalink
working on keyboard accessibility #139
Browse files Browse the repository at this point in the history
  • Loading branch information
shahabyazdi committed Sep 8, 2023
1 parent 3cadeda commit dfe1f35
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 72 deletions.
5 changes: 4 additions & 1 deletion src/components/arrow/arrow.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ export default function Arrow({ direction, onClick, disabled }) {
disabled ? "disabled" : ""
}`}
onClick={onClick}
aria-roledescription={`button to navigate ${direction}`}
aria-roledescription={`button to navigate ${direction.replace(
"rmdp-",
""
)}`}
>
<i className="rmdp-arrow"></i>
</button>
Expand Down
4 changes: 1 addition & 3 deletions src/components/calendar/calendar.css
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,6 @@
cursor: pointer;
position: relative;
color: black;
background: transparent;
border: none;
border-radius: 50%;
}

.rmdp-week-day {
Expand Down Expand Up @@ -252,6 +249,7 @@
margin: 0 5px;
background: transparent;
border: none;
padding: 0;
}

.rmdp-arrow-container:hover {
Expand Down
82 changes: 56 additions & 26 deletions src/components/day_picker/day_picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,32 +126,28 @@ export default function DayPicker({
}

return (
<>
{!parentClassName.includes("hidden") ? (
<button
key={i}
className={parentClassName}
onMouseEnter={() =>
rangeHover && setDateHovered(object.date)
}
onClick={(e) => {
e.preventDefault();
if (!mustDisplayDay(object) || object.disabled)
return;

selectDay(object, monthIndex, numberOfMonths);
}}
>
<span className={className} {...allProps}>
{mustDisplayDay(object) && !object.hidden
? children ?? object.day
: ""}
</span>
</button>
) : (
<span key={i} className={parentClassName}></span>
)}
</>
<div
key={i}
tabIndex={parentClassName.includes("selected") ? 0 : -1}
className={parentClassName}
onMouseEnter={() =>
rangeHover && setDateHovered(object.date)
}
onKeyDown={handleKeyDown}
onClick={() => {
if (!mustDisplayDay(object) || object.disabled) {
return;
}

selectDay(object, monthIndex, numberOfMonths);
}}
>
<span className={className} {...allProps}>
{mustDisplayDay(object) && !object.hidden
? children ?? object.day
: ""}
</span>
</div>
);
})}
</div>
Expand Down Expand Up @@ -286,6 +282,40 @@ export default function DayPicker({

return allProps;
}

function handleKeyDown(e) {
const { currentTarget, key, code } = e;
const { nextSibling, previousSibling, parentNode } = currentTarget;

if (code === "Space" || key === " ") {
e.preventDefault();
currentTarget.click();
} else if (["ArrowRight", "ArrowLeft"].includes(key)) {
focus(key === "ArrowRight" ? nextSibling : previousSibling);
} else if (["ArrowUp", "ArrowDown"].includes(key)) {
const number = key === "ArrowUp" ? -1 : 1;
const allWeeks = Array.from(parentNode.parentNode.childNodes);
const curremtWeek = Array.from(parentNode.childNodes);
const weekIndex = allWeeks.indexOf(parentNode);
const dayIndex = curremtWeek.indexOf(currentTarget);
const nextWeek = allWeeks[weekIndex + number];
const day = nextWeek && nextWeek.childNodes[dayIndex];

focus(day);
}

function focus(node) {
e.preventDefault();

if (!node) return;

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

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

function getMonths(date, showOtherDays, numberOfMonths, weekStartDayIndex) {
Expand Down
5 changes: 2 additions & 3 deletions src/components/header/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,8 @@ export default function Header({
function getButton(direction) {
let handleClick = (e) => {
e.preventDefault();
if(document.activeElement.classList.contains('rmdp-arrow-container')) {
increaseValue(direction === "right" ? 1 : -1);
}

increaseValue(direction === "right" ? 1 : -1);
},
disabled =
(direction === "left" && isPreviousDisable) ||
Expand Down
40 changes: 12 additions & 28 deletions src/plugins/date_panel/date_panel.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
border-radius: 3px;
box-shadow: 0 0 2px var(--rmdp-shadow);
background-color: var(--rmdp-primary);
color: white;
position: relative;
margin: 4px 1px;
overflow: hidden;
}

.rmdp-panel-body li.bg-blue {
Expand All @@ -49,42 +49,26 @@
box-shadow: 0 0 2px 1px var(--rmdp-shadow);
}

.rmdp-panel-body span {
margin: 0 5px;
line-height: 23px;
font-size: 15px;
text-align: start;
flex: 1;
.rmdp-panel-body li button {
color: #fff;
}

.rmdp-panel-body li .b-deselect {
font-family: Arial !important;
align-items: center;
display: inline-flex;
border: none;
cursor: pointer;
height: 12px;
width: 12px;
justify-content: center;
border-radius: 50%;
font-size: 16px;
position: absolute;
right: 5px;
top: 52%;
transform: translateY(-50%) rotate(45deg);
padding: 0;
line-height: 5px;
background: transparent;
background-color: var(--rmdp-primary);
}

.rmdp-panel-body li .b-deselect span {
transform: rotate(45deg);
display: block;
}

.rmdp-panel-body li .b-date {
border: none;
background-color: var(--rmdp-primary);
background-color: transparent;
font-size: 14px;
}

.rmdp-panel-body li .b-deselect:focus {
outline: none;
padding: 4px;
flex: 1;
}

.rmdp-panel-header {
Expand Down
60 changes: 49 additions & 11 deletions src/plugins/date_panel/date_panel.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from "react";
import DateObject from "react-date-object";
import getAllDatesInRange from "../../shared/getAllDatesInRange";
import isArray from "../../shared/isArray";
import getBorderClass from "../../shared/getBorderClass";
Expand Down Expand Up @@ -130,29 +131,25 @@ export default function DatePanel({
>
{[object].flat().map((object, index) => (
<button
onKeyDown={handleKeyDown}
key={index}
type="button"
className="b-date"
onClick={(e) => {
e.preventDefault();
deSelect(date.index);
}}
onClick={() => selectDate(object.date, object.index)}
style={{ cursor: object.date ? "pointer" : "default" }}
ariaDescription={`Date ${object.format} is selected. Click to unselect it.`}
>
{formatFunction ? formatFunction(object) : object.format}
</button>
))}
{date && removeButton && (
<button
onKeyDown={handleKeyDown}
type="button"
ariaDescription={`The date ${object.format} has been selected. Click to deselect it.`}
className="b-deselect"
tabIndex={-1}
onClick={(e) => {
e.preventDefault();
deSelect(date.index);
}}
onClick={() => deSelect(date.index)}
>
+
<span>+</span>
</button>
)}
</li>
Expand All @@ -163,6 +160,20 @@ export default function DatePanel({
</div>
);

function selectDate(date, index) {
handleClick(date ? selectedDate[index] : undefined);

if (!date) return;

setState({
...state,
date: new DateObject(date),
focused: multiple && range ? date : selectedDate[index],
});

handleFocusedDate(selectedDate[index]);
}

function deSelect(index) {
let dates, focused;

Expand Down Expand Up @@ -193,4 +204,31 @@ export default function DatePanel({
function handleClick(date) {
if (onClickDate instanceof Function) onClickDate(date);
}

function handleKeyDown(e) {
const { key, currentTarget } = e;
const li = currentTarget.parentNode;
const list = Array.from(li.parentNode.childNodes);
const index = list.indexOf(li);

if (["ArrowRight", "ArrowLeft"].includes(key)) {
const { nextSibling, previousSibling } = currentTarget;

focus(key === "ArrowRight" ? nextSibling : previousSibling);
} else if (["ArrowUp", "ArrowDown"].includes(key)) {
const number = key === "ArrowUp" ? -1 : 1;
const buttons = Array.from(li.childNodes);
const buttonIndex = buttons.indexOf(currentTarget);
const nextLi = list[index + number];

focus(nextLi && nextLi.childNodes[buttonIndex]);
}

function focus(node) {
if (node) {
e.preventDefault();
node.focus();
}
}
}
}

0 comments on commit dfe1f35

Please sign in to comment.