Skip to content

Commit

Permalink
Accessibility (#1503)
Browse files Browse the repository at this point in the history
* Implement dom-based keyboard navigation for year selection

* Make calendar keyboard navigation also focus-based

* Fix animation freesing because of .focus() in Calendar

* Add proper aria-label's for calendar

* Properly handle focus when switching months

* Announce month and year switching

* Make props for customizing aria-label texts

* Fix type for useKeyDown handler

* Add aria-label for mobile keyboard input button

* Fix Prop inference after changing interfaces

* Implement force quitting picker onKeyDown

* Aria-labels and live regions for date & time picker

* Fix day and clock numbers not autofocusing on appear

* Fix missing container if `reduceAnimations`

* Better default focus management

* Add more keyboard shorcats

* Add accessibility guide

* Fix styles of markdown table

* Fix grammar in accessibility guideline

* Fix crashing on openning invalid date

* Make focus visible when root element of wrapper is focused

* Fix not closing mobile dialog with esc

* Better match material design accessibility spec

* Fix ts error and linters

* Add keyboard navigation cypress tests

* Skip flaky test
  • Loading branch information
dmtrKovalenko authored Feb 13, 2020
1 parent ac082ff commit fd86dc2
Show file tree
Hide file tree
Showing 49 changed files with 1,339 additions and 628 deletions.
1 change: 1 addition & 0 deletions docs/layout/components/navigationMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const navItems = [
{
title: 'Guides',
children: [
{ title: 'Accessibility', href: '/guides/accessibility' },
{ title: 'Form integration', href: '/guides/form-integration' },
{ title: 'CSS overrides', href: '/guides/css-overrides' },
{ title: 'Global format customization', href: '/guides/formats' },
Expand Down
15 changes: 15 additions & 0 deletions docs/layout/styleOverrides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,21 @@ export const createOverrides = (theme: Theme): StyleRules<any> => ({
color: theme.palette.text.primary,
},
li: theme.typography.body1,
'.mui-pickers-markdown-table': {
boxShadow: theme.shadows[3],
backgroundColor: theme.palette.background.paper,
borderCollapse: 'collapse',

'& th, td': {
padding: 16,
...theme.typography.body1,
border: `1px solid ${theme.palette.divider}`,
},

'& th': {
...theme.typography.h6,
},
},
code: {
fontSize: 16,
lineHeight: 1.4,
Expand Down
3 changes: 2 additions & 1 deletion docs/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const withImages = require('next-images');
const withTypescript = require('@zeit/next-typescript');
const rehypePrism = require('@mapbox/rehype-prism');
const headings = require('./utils/anchor-autolink');
const tableStyler = require('./utils/table-styler');
const withTM = require('next-transpile-modules');
const slug = require('remark-slug');
const webpack = require('webpack');
Expand All @@ -13,7 +14,7 @@ const withMDX = require('@zeit/next-mdx')({
extension: /\.(md|mdx)?$/,
options: {
hastPlugins: [rehypePrism],
mdPlugins: [slug, headings],
mdPlugins: [slug, headings, tableStyler],
},
});

Expand Down
4 changes: 2 additions & 2 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@types/prismjs": "^1.9.1",
"@types/react": "^16.8.13",
"@types/react-kawaii": "^0.11.0",
"@types/react-redux": "^7.1.7",
"@types/sinon": "^7.0.13",
"@zeit/next-bundle-analyzer": "^0.1.2",
"@zeit/next-css": "^1.0.1",
Expand Down Expand Up @@ -71,8 +72,7 @@
"sinon": "^7.3.2",
"styled-jsx": "^3.2.4",
"ts-loader": "^6.0.2",
"typescript": "^3.4.4",
"@types/react-redux": "^7.1.7"
"typescript": "^3.4.4"
},
"devDependencies": {
"dotenv": "^7.0.0",
Expand Down
1 change: 0 additions & 1 deletion docs/pages/demo/datepicker/BasicDatePicker.example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ function BasicDatePicker() {
<DatePicker
label="Basic example"
value={selectedDate}
// DialogProps={{ 'aria-activedescendant': '12' }}
onChange={date => handleDateChange(date)}
/>
);
Expand Down
18 changes: 18 additions & 0 deletions docs/pages/guides/Accessibility.example.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { useState } from 'react';
import { DatePicker } from '@material-ui/pickers';

function BasicDatePicker() {
const [selectedDate, handleDateChange] = useState(new Date());

return (
<DatePicker
disableMaskedInput
placeholder="mm/dd/yyyy"
label="Accessible"
value={selectedDate}
onChange={date => handleDateChange(date)}
/>
);
}

export default BasicDatePicker;
58 changes: 58 additions & 0 deletions docs/pages/guides/accessibility.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Ad from '_shared/Ad';
import Example from '_shared/Example';
import PageMeta from '_shared/PageMeta';
import * as Accessibility from './Accessibility.example';

<PageMeta title="Accessiblity" description="Accessibility guideline for @material-ui/pickers" />

## Accessibility

<Ad />

Pickers accessibility is highly impoertant, because this control is becoming completely unusable if there is
no appropriate focus managment.

The dialog contains a calendar that uses the [grid](https://www.w3.org/TR/wai-aria-practices/#grid) pattern to present buttons that enable the user to choose a day from the calendar.
Choosing a date from the calendar closes the dialog and populates the date input field. When the dialog is opened,
if the input field is empty, or does not contain a valid date, then the current date is focused in the calendar.
Otherwise, the focus is placed on the day in the calendar that matches the value of the date input field.
It is possible to navigate throught the calendar, year selection and clock with only keyboard.

But still there are some limitations:

- You need to provide accessible placeholder (`mm/dd/yyyy`) according to used format and locale
- Masked input is not really well announcing via screen readers, so you may consider disable it

### Example

Here is working accessible example, compare it to the [wia-aria datepicker dialog example](https://www.w3.org/TR/wai-aria-practices/examples/dialog-modal/datepicker-dialog.html)

<Example source={Accessibility} />

### Keyboard shortcats

Here is the list of avaialble keyboard shortcats allows to control the date and time pickers with only keyboard.

#### DatePicker

| Shortcat | Action |
| ------------ | ------------------------------------------------------------------------------------- |
| ArrowUp | Moves focus to the same day of the previous week. |
| ArrowDown | Moves focus to the same day of the next week. |
| ArrowRight | Moves focus to the next day. |
| ArrowLeft | Moves focus to the previous day. |
| Home | Moves focus to the first day (e.g Monday) of the current week. |
| End | Moves focus to the last day (e.g. Sunday) of the current week. |
| Esc | Close dialog or popover |
| Space, Enter | Choose currently focused year or date. Closing picker if current view is the last one |

#### TimePicker

| Shortcat | Action |
| ------------ | --------------------------------------------------------------------------------------- |
| ArrowUp | Incrment (hours/minutes/seconds) according to the used step |
| ArrowDown | Decrmeent (hours/minutes/seconds) according to the used step |
| Home | Select maximal value of current clock type (hours/minutes/seconds) |
| End | Select minimal value of current clock type (hours/minutes/seconds) |
| Esc | Close dialog or popover |
| Space, Enter | Accept currently selected selected value, move to the next view or close popover/dialog |
16 changes: 15 additions & 1 deletion docs/pages/regression/Regression.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ import LeftArrowIcon from '@material-ui/icons/KeyboardArrowLeft';
import RightArrowIcon from '@material-ui/icons/KeyboardArrowRight';
import { Grid, Typography } from '@material-ui/core';
import { MuiPickersContext } from '@material-ui/pickers';
import { MobileDatePicker, DesktopDatePicker } from '@material-ui/pickers';
import { createRegressionDay as createRegressionDayRenderer } from './RegressionDay';
import {
MobileDatePicker,
DesktopDatePicker,
MobileTimePicker,
DesktopTimePicker,
} from '@material-ui/pickers';

function Regression() {
const utils = useContext(MuiPickersContext);
Expand Down Expand Up @@ -50,6 +55,15 @@ function Regression() {
<MobileDatePicker disabled id="disabled" {...sharedProps} />
<MobileDatePicker readOnly id="readonly" {...sharedProps} />
</Grid>

<Typography align="center" variant="h4" component="span" gutterBottom>
TimePicker
</Typography>

<Grid container justify="center" wrap="wrap">
<MobileTimePicker id="mobile-timepicker" value={date} onChange={changeDate} />
<DesktopTimePicker id="desktop-timepicker" value={date} onChange={changeDate} />
</Grid>
</div>
);
}
Expand Down
Loading

1 comment on commit fd86dc2

@vercel
Copy link

@vercel vercel bot commented on fd86dc2 Feb 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.