Skip to content

Commit

Permalink
Makes the DateRangePicker and SingleDatePicker keyboard accessible
Browse files Browse the repository at this point in the history
- Adds screen reader text to the input to describe how to enter the calendar
- Adds arrow navigation to the calendar itself
- Adds a keyboard shortcuts panel that pops up on top of the calendar
- Adds screen reader text to each CalendarDay
  • Loading branch information
Maja Wichrowska committed Apr 6, 2017
1 parent 5ba9930 commit 5183125
Show file tree
Hide file tree
Showing 33 changed files with 2,293 additions and 154 deletions.
1 change: 1 addition & 0 deletions constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ module.exports = {
ANCHOR_RIGHT: 'right',

DAY_SIZE: 39,
BLOCKED_MODIFIER: 'blocked',
};
20 changes: 19 additions & 1 deletion css/CalendarDay.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
@import "variables";

// This order is important.
.CalendarDay {
border: 1px solid lighten($react-dates-color-border-light, 3);
padding: 0;
Expand All @@ -9,12 +8,31 @@
cursor: pointer;
width: 39px;
height: 38px;
}

.CalendarDay__button {
position: relative;
height: 100%;
width: 100%;
text-align: center;
background: none;
border: 0;
margin: 0;
padding: 0;
color: inherit;
font: inherit;
line-height: normal;
overflow: visible;
cursor: pointer;
box-sizing: border-box;

&:active {
background: darken($react-dates-color-white, 5%);
outline: 0;
}
}

// This order is important.
.CalendarDay--highlighted-calendar {
background: $react-dates-color-highlighted;
color: $react-dates-color-gray;
Expand Down
4 changes: 2 additions & 2 deletions css/DateRangePicker.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
}

.DateRangePicker__picker--direction-left {
left: 0;
left: 0;
}

.DateRangePicker__picker--direction-right {
right: 0;
right: 0;
}

.DateRangePicker__picker--portal {
Expand Down
161 changes: 161 additions & 0 deletions css/DayPickerKeyboardShortcuts.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
.DayPickerKeyboardShortcuts__show,
.DayPickerKeyboardShortcuts__close {
background: none;
border: 0;
color: inherit;
font: inherit;
line-height: normal;
overflow: visible;
padding: 0;
cursor: pointer;

&:active {
outline: none;
}
}

.DayPickerKeyboardShortcuts__show {
width: 22px;
position: absolute;
}

.DayPickerKeyboardShortcuts__show--bottom-right {
border-top: 26px solid $react-dates-color-white;
border-right: 33px solid $react-dates-color-primary;
bottom: 0;
right: 0;

&:hover {
border-right: 33px solid #008489;
}

.DayPickerKeyboardShortcuts__show_span {
bottom: 0;
right: -28px;
}
}

.DayPickerKeyboardShortcuts__show--top-right {
border-bottom: 26px solid $react-dates-color-white;
border-right: 33px solid $react-dates-color-primary;
top: 0;
right: 0;

&:hover {
border-right: 33px solid #008489;
}

.DayPickerKeyboardShortcuts__show_span {
top: 1px;
right: -28px;
}
}

.DayPickerKeyboardShortcuts__show--top-left {
border-bottom: 26px solid $react-dates-color-white;
border-left: 33px solid $react-dates-color-primary;
top: 0;
left: 0;

&:hover {
border-left: 33px solid #008489;
}

.DayPickerKeyboardShortcuts__show_span {
top: 1px;
left: -28px;
}
}

.DayPickerKeyboardShortcuts__show_span {
color: $react-dates-color-white;
position: absolute;
}

.DayPickerKeyboardShortcuts__panel {
background: $react-dates-color-white;
border: 1px solid $react-dates-color-border;
border-radius: 2px;
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 2;
padding: 22px;
margin: 33px;
}

.DayPickerKeyboardShortcuts__title {
font-size: 16px;
font-weight: bold;
margin: 0;
}

.DayPickerKeyboardShortcuts__list {
list-style: none;
padding: 0;

}

.DayPickerKeyboardShortcuts__close {
position: absolute;
right: 22px;
top: 22px;
z-index: 2;

svg {
height: 15px;
width: 15px;
fill: $react-dates-color-gray-lighter;

&:hover,
&:focus {
fill: $react-dates-color-gray-light;
}
}

&:active {
outline: none;
}
}

.KeyboardShortcutRow {
margin: 6px 0;
}

.KeyboardShortcutRow__key-container {
display: inline-block;
width: 15%;
white-space: nowrap;
text-align: right;
margin-right: 6px;
}

.KeyboardShortcutRow__key {
font-family: monospace;
font-size: 12px;
text-transform: uppercase;
background: $react-dates-color-gray-lightest;
padding: 2px 6px;
}

.KeyboardShortcutRow__action {
display: inline-block;
}

.DayPickerKeyboardShortcuts__panel--block {
.KeyboardShortcutRow {
margin-bottom: 16px;
}

.KeyboardShortcutRow__key-container {
width: auto;
text-align: left;
display: inline;
}

.KeyboardShortcutRow__action {
display: inline;
}
}
1 change: 1 addition & 0 deletions css/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@import 'CalendarMonthGrid';
@import 'DayPicker';
@import 'DayPickerNavigation';
@import 'DayPickerKeyboardShortcuts';
@import 'DateInput';
@import 'DateRangePicker';
@import 'DateRangePickerInput';
Expand Down
2 changes: 2 additions & 0 deletions css/variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ $react-dates-spacing-vertical-picker: 72px !default;

$react-dates-color-primary: #00a699 !default;
$react-dates-color-primary-dark: #00514a !default;
$react-date-color-primary-dark-1: #008489 !default;
$react-dates-color-primary-shade-1: #33dacd !default;
$react-dates-color-primary-shade-2: #66e2da !default;
$react-dates-color-primary-shade-3: #80e8e0 !default;
Expand All @@ -15,6 +16,7 @@ $react-dates-color-gray: #565a5c !default;
$react-dates-color-gray-dark: darken($react-dates-color-gray, 10.5%) !default;
$react-dates-color-gray-light: lighten($react-dates-color-gray, 17.8%) !default; // #82888a
$react-dates-color-gray-lighter: lighten($react-dates-color-gray, 45%) !default; // #cacccd
$react-dates-color-gray-lightest: lighten($react-dates-color-gray, 60%) !default;
$react-dates-color-highlighted: #ffe8bc !default;

$react-dates-color-border: #dbdbdb !default;
Expand Down
9 changes: 5 additions & 4 deletions examples/DateRangePickerWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import omit from 'lodash.omit';

import DateRangePicker from '../src/components/DateRangePicker';

import { DateRangePickerPhrases } from '../src/defaultPhrases';
import DateRangePickerShape from '../src/shapes/DateRangePickerShape';
import { START_DATE, END_DATE, HORIZONTAL_ORIENTATION, ANCHOR_LEFT } from '../constants';
import isInclusivelyAfterDay from '../src/utils/isInclusivelyAfterDay';
Expand Down Expand Up @@ -74,10 +75,7 @@ const defaultProps = {
// internationalization
displayFormat: () => moment.localeData().longDateFormat('L'),
monthFormat: 'MMMM YYYY',
phrases: {
closeDatePicker: 'Close',
clearDates: 'Clear Dates',
},
phrases: DateRangePickerPhrases,
};

class DateRangePickerWrapper extends React.Component {
Expand Down Expand Up @@ -112,6 +110,9 @@ class DateRangePickerWrapper extends React.Component {
render() {
const { focusedInput, startDate, endDate } = this.state;

// autoFocus, autoFocusEndDate, initialStartDate and initialEndDate are helper props for the
// example wrapper but are not props on the SingleDatePicker itself and
// thus, have to be omitted.
const props = omit(this.props, [
'autoFocus',
'autoFocusEndDate',
Expand Down
16 changes: 11 additions & 5 deletions examples/SingleDatePickerWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import omit from 'lodash.omit';

import SingleDatePicker from '../src/components/SingleDatePicker';

import { SingleDatePickerPhrases } from '../src/defaultPhrases';
import SingleDatePickerShape from '../src/shapes/SingleDatePickerShape';
import { HORIZONTAL_ORIENTATION, ANCHOR_LEFT } from '../constants';
import isInclusivelyAfterDay from '../src/utils/isInclusivelyAfterDay';
Expand All @@ -13,6 +14,7 @@ const propTypes = {
// example props for the demo
autoFocus: PropTypes.bool,
initialDate: momentPropTypes.momentObj,

...omit(SingleDatePickerShape, [
'date',
'onDateChange',
Expand Down Expand Up @@ -61,10 +63,7 @@ const defaultProps = {
// internationalization props
displayFormat: () => moment.localeData().longDateFormat('L'),
monthFormat: 'MMMM YYYY',
phrases: {
closeDatePicker: 'Close',
clearDate: 'Clear Date',
},
phrases: SingleDatePickerPhrases,
};

class SingleDatePickerWrapper extends React.Component {
Expand All @@ -90,9 +89,16 @@ class SingleDatePickerWrapper extends React.Component {
render() {
const { focused, date } = this.state;

// autoFocus and initialDate are helper props for the example wrapper but are not
// props on the SingleDatePicker itself and thus, have to be omitted.
const props = omit(this.props, [
'autoFocus',
'initialDate',
]);

return (
<SingleDatePicker
{...this.props}
{...props}
id="date_input"
date={date}
focused={focused}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"array-includes": "^3.0.2",
"classnames": "^2.2.5",
"consolidated-events": "^1.0.1",
"lodash.throttle": "^4.1.1",
"react-moment-proptypes": "^1.3.0",
"react-portal": "^3.0.0"
},
Expand Down

0 comments on commit 5183125

Please sign in to comment.