Skip to content

Commit

Permalink
Improve date parts selection flow (mui#1923)
Browse files Browse the repository at this point in the history
  • Loading branch information
dmtrKovalenko authored Jul 6, 2020
1 parent e4c2bdd commit 853e5d2
Show file tree
Hide file tree
Showing 47 changed files with 542 additions and 396 deletions.
6 changes: 3 additions & 3 deletions docs/pages/demo/datepicker/CustomInput.example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ function CustomInput() {
label="Advanced keyboard"
value={selectedDate}
onChange={date => handleDateChange(date)}
renderInput={({ ref, inputProps, InputProps }) => (
<InputContainer ref={ref}>
<input {...inputProps} />
renderInput={({ inputRef, inputProps, InputProps }) => (
<InputContainer>
<input ref={inputRef} {...inputProps} />
{InputProps?.endAdornment}
</InputContainer>
)}
Expand Down
1 change: 0 additions & 1 deletion docs/pages/demo/datepicker/DatePickers.example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ function DatePickersVariants(props) {
/>

<DesktopDatePicker
autoOk
label="For desktop"
minDate={new Date('2017-01-01')}
value={selectedDate}
Expand Down
2 changes: 0 additions & 2 deletions docs/pages/demo/datepicker/StaticDatePicker.example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export default function StaticDatePickerExample() {
return (
<React.Fragment>
<StaticDatePicker
autoOk
displayStaticWrapperAs="desktop"
openTo="year"
value={date}
Expand All @@ -24,7 +23,6 @@ export default function StaticDatePickerExample() {
/>

<StaticDatePicker
autoOk
orientation="landscape"
openTo="date"
value={date}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useState } from 'react';
import AlarmIcon from '@material-ui/icons/Alarm';
import SnoozeIcon from '@material-ui/icons/Snooze';
import ClockIcon from '@material-ui/icons/AccessTime';
import TextField from '@material-ui/core/TextField';
import ClockIcon from '@material-ui/icons/AccessTime';
import { DateTimePicker, MobileDateTimePicker } from '@material-ui/pickers';

function CustomDateTimePicker(props) {
Expand All @@ -12,7 +12,6 @@ function CustomDateTimePicker(props) {
return (
<React.Fragment>
<DateTimePicker
autoOk
disableFuture
hideTabs
showTodayButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ function DateTimePickerDemo(props) {
return (
<React.Fragment>
<MobileDateTimePicker
autoOk
disableFuture
value={selectedDate}
onChange={handleDateChange}
Expand Down
1 change: 0 additions & 1 deletion docs/pages/demo/timepicker/StaticTimePicker.example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export default function StaticTimePickerExample() {
return (
<React.Fragment>
<StaticTimePicker
autoOk
openTo="hours"
value={date}
onChange={date => handleDateChange(date)}
Expand Down
3 changes: 1 addition & 2 deletions docs/pages/guides/Accessibility.example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ function BasicDatePicker() {

return (
<DatePicker
renderInput={props => <TextField {...props} />}
disableMaskedInput
label="Accessible"
value={selectedDate}
onChange={date => handleDateChange(date)}
renderInput={props => <TextField {...props} />}
/>
);
}
Expand Down
1 change: 0 additions & 1 deletion docs/pages/guides/FormikOurValidation.example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ function DatePickerField({

return (
<DatePicker
autoOk
clearable
minDate={minDate}
maxDate={maxDate}
Expand Down
5 changes: 2 additions & 3 deletions docs/pages/guides/FormikValidationSchema.example.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// @ts-nocheck
import React from 'react';
import { date, object } from 'yup';
import { Grid } from '@material-ui/core';
import TextField from '@material-ui/core/TextField';
import { date, object } from 'yup';
import Grid from '@material-ui/core/Grid';
import { Formik, Form, Field, FieldProps } from 'formik';
import { DatePicker, BaseDatePickerProps } from '@material-ui/pickers';

Expand All @@ -22,7 +22,6 @@ function DatePickerField({

return (
<DatePicker
autoOk
clearable
minDate={minDate}
maxDate={maxDate}
Expand Down
24 changes: 17 additions & 7 deletions docs/pages/guides/accessibility.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,31 @@ import * as Accessibility from './Accessibility.example';

<Ad />

Pickers accessibility is highly impoertant, because this control is becoming completely unusable if there is
no appropriate focus managment.
Pickers accessibility is highly important, because this control is becoming completely unusable for disabled people
if there is no appropriate focus managment and keyboard control.

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.
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:
#### 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
- `placeholder` with helper text is completely important to be set for people with disabilities.
- `disableCloseOnSelect` prop makes picker less acessible for Desktop users because it will not be closed by `Enter` or `Space`.
- `allowKeyboardControl` is required for proper a11y. **Important**: It is by default disabled for **all Static** components.
It's necessary to pass it manually if you are rendering datepicker in custom popper/popover or modal in order to enable focus managment and keyboard control:

### Example
```jsx
<StaticDatePicker
allowKeyboardControl
...
/>
```

### Test accessibility

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)

Expand Down
2 changes: 0 additions & 2 deletions docs/pages/regression/Regression.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,11 @@ function Regression() {
{...sharedProps}
/>
<DesktopDatePicker
autoOk
{...makeRenderInputProp({ id: 'keyboard-mask-datepicker' })}
{...sharedProps}
inputFormat="MM/dd/yyyy"
/>
<DesktopDatePicker
autoOk
{...makeRenderInputProp({ id: 'keyboard-invalid-mask-datepicker' })}
{...sharedProps}
mask="__"
Expand Down
60 changes: 35 additions & 25 deletions docs/prop-types.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions e2e/component/DateTimePicker.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as React from 'react';
import { DIALOG_WIDTH } from '../../lib/src/constants/dimensions';
import { mountPickerWithState, mountStaticPicker } from '../test-utils';
import { StaticDateTimePicker, MobileDateTimePicker } from '@material-ui/pickers';

describe('<DateTimePicker />', () => {
it('Renders and show todays date', () => {
mountStaticPicker(defaultProps => <StaticDateTimePicker {...defaultProps} />);

cy.contains('2017');
cy.contains('Oct 7');
cy.contains('07:36');

cy.percySnapshot('<DateTimePicker />', {
widths: [DIALOG_WIDTH],
});
});

it('Proper flow for date & time picking', () => {
mountPickerWithState(defaultProps => <MobileDateTimePicker openTo="year" {...defaultProps} />);

cy.get('input').click();

// Year
cy.findByText('2015').click();
cy.get('input').should('have.value', '10/07/2015 7:36 PM');

// Date
cy.findByLabelText('next month')
.click()
.click();
cy.findByLabelText('Dec 22, 2015').click();
cy.get('input').should('have.value', '12/22/2015 7:36 PM');

// Hour
cy.findByRole('menu').trigger('mouseup', { buttons: 1, offsetX: 66, offsetY: 157 });
cy.get('input').should('have.value', '12/22/2015 8:36 PM');

// Minute
cy.findByRole('menu').trigger('mouseup', {
buttons: 1,
offsetX: 222,
offsetY: 180,
});

cy.get('input').should('have.value', '12/22/2015 8:20 PM');
});
});
3 changes: 2 additions & 1 deletion e2e/test-utils.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import * as React from 'react';
import parse from 'date-fns/parseISO';
import DateFnsAdapter from '@material-ui/pickers/adapter/date-fns';
import TextField, { TextFieldProps } from '@material-ui/core/TextField';
import { mount } from 'cypress-react-unit-test';
import { DIALOG_WIDTH } from '../lib/src/constants/dimensions';
import { LocalizationProvider, StaticDatePickerProps } from '@material-ui/pickers';

// Time of the first commit to the pickers ❤️
const momentInTime = new Date('2017-10-07T19:36:00.000Z');
const momentInTime = parse('2017-10-07T19:36:00.000');
const mockRequiredProps = {
reduceAnimations: true, // speedup tests
value: momentInTime,
Expand Down
Loading

0 comments on commit 853e5d2

Please sign in to comment.