Skip to content

Commit

Permalink
Fix keyboard navigation
Browse files Browse the repository at this point in the history
Original message by greglo in PR #2084:

Keyboard navigation is broken for the date range picker. The following
bugs exist:

When passing through the component with tab-navigation, after exiting
the end-date input the dropdown does not close. When attempting to enter
values into the end-date dropdown, users would have to tab backwards
back to the dropdown to enter values. The simplest and clearest solution
that came to be is simply to put the day picker after the currently
active input. In this way, the dropdown always appears next in the
tab-order to the input the user has selected. The existing blur handler
in the dropdown means that tabbing through the component will leave the
dropdown closed at the end.

The react keys ensure that the element is just moved over in the DOM and
so there is no flickering.

Fixes #1809
  • Loading branch information
Daniel M committed Nov 10, 2021
1 parent 6c2cb61 commit 61559f4
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 2 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
"react-outside-click-handler": "^1.3.0",
"react-portal": "^4.2.1",
"react-with-direction": "^1.3.1",
"react-with-styles": "^4.1.0",
"react-with-styles": "~4.1.0",
"react-with-styles-interface-css": "^6.0.0"
},
"peerDependencies": {
Expand Down
1 change: 1 addition & 0 deletions src/components/DateRangePicker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ class DateRangePicker extends React.PureComponent {
/* eslint-disable jsx-a11y/click-events-have-key-events */
return (
<div
key="day-picker"
ref={this.setDayPickerContainerRef}
{...css(
styles.DateRangePicker_picker,
Expand Down
4 changes: 3 additions & 1 deletion src/components/DateRangePickerInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ function DateRangePickerInput({
regular={regular}
/>

{children}
{!isEndDateFocused && children}

{
<div
Expand Down Expand Up @@ -289,6 +289,8 @@ function DateRangePickerInput({
regular={regular}
/>

{isEndDateFocused && children}

{showClearDates && (
<button
type="button"
Expand Down
61 changes: 61 additions & 0 deletions test/components/DateRangePicker_spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import DateRangePicker, { PureDateRangePicker } from '../../src/components/DateR

import DateRangePickerInputController from '../../src/components/DateRangePickerInputController';
import DayPickerRangeController from '../../src/components/DayPickerRangeController';
import DayPicker from '../../src/components/DayPicker';

import {
HORIZONTAL_ORIENTATION,
Expand All @@ -17,6 +18,49 @@ import {

const describeIfWindow = typeof document === 'undefined' ? describe.skip : describe;

class DateRangePickerWrapper extends React.Component {
constructor(props) {
super(props);

this.state = {
focusedInput: null,
startDate: null,
endDate: null,
};

this.onDatesChange = this.onDatesChange.bind(this);
this.onFocusChange = this.onFocusChange.bind(this);
}

onDatesChange({ startDate, endDate }) {
this.setState({ startDate, endDate });
}

onFocusChange(focusedInput) {
this.setState({ focusedInput });
}

render() {
const { focusedInput, startDate, endDate } = this.state;

return (
<div>
<DateRangePicker
{...this.props}
onDatesChange={this.onDatesChange}
onFocusChange={this.onFocusChange}
focusedInput={focusedInput}
startDate={startDate}
endDate={endDate}
/>
<button type="button">
Dummy button
</button>
</div>
);
}
}

const requiredProps = {
onDatesChange: () => {},
onFocusChange: () => {},
Expand Down Expand Up @@ -539,6 +583,23 @@ describe('DateRangePicker', () => {
});
});

describeIfWindow('day picker position', () => {
it('day picker is opened after the end date input when end date input is focused', () => {
const wrapper = mount((
<DateRangePickerWrapper
startDateId="startDate"
endDateId="endDate"
/>
));
expect(wrapper.find(DayPicker)).to.have.length(0);
wrapper.find('input').at(0).simulate('focus'); // when focusing on start date the day picker is rendered after the start date input
expect(wrapper.find('DateRangePickerInput').children().childAt(1).find(DayPicker)).to.have.length(1);
wrapper.find('input').at(1).simulate('focus'); // when focusing on end date the day picker is rendered after the end date input
expect(wrapper.find('DateRangePickerInput').children().childAt(1).find(DayPicker)).to.have.length(0);
expect(wrapper.find('DateRangePickerInput').children().childAt(3).find(DayPicker)).to.have.length(1);
});
});

describeIfWindow('#onDayPickerBlur', () => {
it('sets state.isDateRangePickerInputFocused to true', () => {
const wrapper = shallow((
Expand Down

0 comments on commit 61559f4

Please sign in to comment.