Skip to content

Commit

Permalink
Add other keyboard interactions
Browse files Browse the repository at this point in the history
  • Loading branch information
Maja Wichrowska committed Feb 25, 2017
1 parent 771adbc commit 3cc2495
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 139 deletions.
35 changes: 19 additions & 16 deletions css/CalendarDay.scss
Original file line number Diff line number Diff line change
@@ -1,21 +1,5 @@
@import "variables";

// 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;

// This order is important.
.CalendarDay {
border: 1px solid lighten($react-dates-color-border-light, 3);
padding: 0;
Expand All @@ -24,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
1 change: 1 addition & 0 deletions css/DayPickerNavigation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

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

Expand Down
11 changes: 7 additions & 4 deletions src/components/CalendarDay.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,25 @@ export default class CalendarDay extends React.Component {
isOutsideDay,
modifiers,
renderDay,
isFocused,
} = this.props;

const className = cx('CalendarDay', {
'CalendarDay--outside': !day || isOutsideDay,
}, getModifiersForDay(modifiers, day).map(mod => `CalendarDay--${mod}`));

return (day ?
<td>
<td className={className}>
<button
ref={(ref) => { this.buttonRef = ref; }}
type="button"
className={className}
aria-label={day.format('LL')}
ref={(ref) => { this.buttonRef = ref; }}
className="CalendarDay__button"
aria-label={`${day.format('dddd')}. ${day.format('LL')}`}
onMouseEnter={e => this.onDayMouseEnter(day, e)}
onMouseLeave={e => this.onDayMouseLeave(day, e)}
onMouseUp={e => e.currentTarget.blur()}
onClick={e => this.onDayClick(day, e)}
tabIndex={isFocused ? 0 : -1}
>
{renderDay ? renderDay(day) : day.format('D')}
</button>
Expand Down
6 changes: 4 additions & 2 deletions src/components/CalendarMonthGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,17 @@ export default class CalendarMonthGrid extends React.Component {

const { months } = this.state;

const isHorizontal = orientation === HORIZONTAL_ORIENTATION;

const className = cx('CalendarMonthGrid', {
'CalendarMonthGrid--horizontal': orientation === HORIZONTAL_ORIENTATION,
'CalendarMonthGrid--horizontal': isHorizontal,
'CalendarMonthGrid--vertical': orientation === VERTICAL_ORIENTATION,
'CalendarMonthGrid--vertical-scrollable': orientation === VERTICAL_SCROLLABLE,
'CalendarMonthGrid--animating': isAnimating,
});

const style = Object.assign({
width: (numberOfMonths + 1) * calendarMonthWidth,
width: isHorizontal ? (numberOfMonths + 1) * calendarMonthWidth : calendarMonthWidth,
}, getTransformStyles(transformValue));

return (
Expand Down
6 changes: 3 additions & 3 deletions src/components/DateInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ export default class DateInput extends React.Component {
}

componentDidUpdate(prevProps) {
const { focused } = this.props;
if (prevProps.focused === focused) return;
const { focused, hasFocus } = this.props;
if (prevProps.focused === focused && prevProps.hasFocus === hasFocus) return;

if (focused) {
if (focused && hasFocus) {
this.inputRef.focus();
this.inputRef.select();
} else {
Expand Down
53 changes: 43 additions & 10 deletions src/components/DateRangePicker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ const defaultProps = {
phrases: {
closeDatePicker: 'Close',
clearDates: 'Clear Dates',
jumpToPrevMonth: 'Jump to previous month',
jumpToNextMonth: 'Jump to next month',
},
};

Expand All @@ -88,12 +90,14 @@ export default class DateRangePicker extends React.Component {
super(props);
this.state = {
dayPickerContainerStyles: {},
isDateRangePickerInputFocused: false,
isDayPickerFocused: false,
};

this.onOutsideClick = this.onOutsideClick.bind(this);
this.onFocusDayPicker = this.onFocusDayPicker.bind(this);
this.onBlurDayPicker = this.onBlurDayPicker.bind(this);
this.onDateRangePickerInputFocus = this.onDateRangePickerInputFocus.bind(this);
this.onDayPickerFocus = this.onDayPickerFocus.bind(this);
this.onDayPickerBlur = this.onDayPickerBlur.bind(this);

this.responsivizePickerPosition = this.responsivizePickerPosition.bind(this);
}
Expand All @@ -108,6 +112,10 @@ export default class DateRangePicker extends React.Component {
this.responsivizePickerPosition();
}

componentWillReceiveProps(nextProps) {
// set daterangepickinputfocused to true if focusedinput went from nothing to something
}

shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}
Expand All @@ -127,17 +135,37 @@ export default class DateRangePicker extends React.Component {
const { onFocusChange } = this.props;
if (!this.isOpened()) return;

this.setState({
isDateRangePickerInputFocused: false,
isDayPickerFocused: false,
});

onFocusChange(null);
}

onFocusDayPicker() {
onDateRangePickerInputFocus(focusedInput) {
const { onFocusChange } = this.props;

if (focusedInput) {
this.setState({
isDateRangePickerInputFocused: true,
isDayPickerFocused: false,
});
}

onFocusChange(focusedInput);
}

onDayPickerFocus() {
this.setState({
isDateRangePickerInputFocused: false,
isDayPickerFocused: true,
});
}

onBlurDayPicker() {
onDayPickerBlur() {
this.setState({
isDateRangePickerInputFocused: true,
isDayPickerFocused: false,
});
}
Expand Down Expand Up @@ -238,6 +266,7 @@ export default class DateRangePicker extends React.Component {
keepOpenOnDateSelect,
renderDay,
initialVisibleMonth,
phrases: { jumpToPrevMonth, jumpToNextMonth },
} = this.props;
const { dayPickerContainerStyles, isDayPickerFocused } = this.state;

Expand Down Expand Up @@ -278,7 +307,11 @@ export default class DateRangePicker extends React.Component {
keepOpenOnDateSelect={keepOpenOnDateSelect}
renderDay={renderDay}
isFocused={isDayPickerFocused}
onBlur={this.onBlurDayPicker}
onBlur={this.onDayPickerBlur}
phrases={{
jumpToPrevMonth,
jumpToNextMonth,
}}
/>

{withFullScreenPortal &&
Expand Down Expand Up @@ -321,10 +354,10 @@ export default class DateRangePicker extends React.Component {
reopenPickerOnClearDates,
keepOpenOnDateSelect,
onDatesChange,
onFocusChange,
renderDay,
} = this.props;

const { isDateRangePickerInputFocused } = this.state;

const onOutsideClick = (!withPortal && !withFullScreenPortal) ? this.onOutsideClick : undefined;

return (
Expand Down Expand Up @@ -352,11 +385,11 @@ export default class DateRangePicker extends React.Component {
isOutsideRange={isOutsideRange}
withFullScreenPortal={withFullScreenPortal}
onDatesChange={onDatesChange}
onFocusChange={onFocusChange}
renderDay={renderDay}
onArrowDown={this.onFocusDayPicker}
onFocusChange={this.onDateRangePickerInputFocus}
onArrowDown={this.onDayPickerFocus}
phrases={phrases}
screenReaderMessage={screenReaderInputMessage}
isFocused={isDateRangePickerInputFocused}
/>

{this.maybeRenderDayPickerWithPortal()}
Expand Down
24 changes: 16 additions & 8 deletions src/components/DateRangePickerInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const propTypes = forbidExtraProps({
onClearDates: PropTypes.func,
onArrowDown: PropTypes.func,


startDate: PropTypes.string,
startDateValue: PropTypes.string,
endDate: PropTypes.string,
Expand All @@ -44,6 +43,7 @@ const propTypes = forbidExtraProps({

// i18n
phrases: PropTypes.shape({
focusStartDate: PropTypes.node,
clearDates: PropTypes.node,
}),
});
Expand Down Expand Up @@ -80,7 +80,8 @@ const defaultProps = {

// i18n
phrases: {
clearDates: 'Clear Dates',
focusStartDate: 'Focus on start date',
clearDates: 'Clear dates',
},
};

Expand Down Expand Up @@ -137,6 +138,7 @@ export default class DateRangePickerInput extends React.Component {
customInputIcon,
customArrowIcon,
phrases,
isFocused,
} = this.props;

const inputIcon = customInputIcon || (<CalendarIcon />);
Expand All @@ -149,12 +151,14 @@ export default class DateRangePickerInput extends React.Component {
})}
>
{(showDefaultInputIcon || customInputIcon !== null) &&
<span
<button
type="button"
className="DateRangePickerInput__calendar-icon"
aria-label={phrases.focusStartDate}
onClick={onStartDateFocus}
>
{inputIcon}
</span>
</button>
}
<DateInput
id={startDateId}
Expand All @@ -163,6 +167,7 @@ export default class DateRangePickerInput extends React.Component {
inputValue={startDateValue}
screenReaderMessage={screenReaderMessage}
focused={isStartDateFocused}
hasFocus={isFocused}
disabled={disabled}
required={required}
showCaret={showCaret}
Expand All @@ -173,7 +178,11 @@ export default class DateRangePickerInput extends React.Component {
onKeyDownArrowDown={onArrowDown}
/>

<div className="DateRangePickerInput__arrow">
<div
className="DateRangePickerInput__arrow"
aria-hidden="true"
role="presentation"
>
{arrowIcon}
</div>

Expand All @@ -184,6 +193,7 @@ export default class DateRangePickerInput extends React.Component {
inputValue={endDateValue}
screenReaderMessage={screenReaderMessage}
focused={isEndDateFocused}
hasFocus={isFocused}
disabled={disabled}
required={required}
showCaret={showCaret}
Expand All @@ -197,6 +207,7 @@ export default class DateRangePickerInput extends React.Component {
{showClearDates &&
<button
type="button"
aria-label={phrases.clearDates}
className={cx('DateRangePickerInput__clear-dates', {
'DateRangePickerInput__clear-dates--hide': !(startDate || endDate),
'DateRangePickerInput__clear-dates--hover': isClearDatesHovered,
Expand All @@ -205,9 +216,6 @@ export default class DateRangePickerInput extends React.Component {
onMouseLeave={this.onClearDatesMouseLeave}
onClick={onClearDates}
>
<span className="screen-reader-only">
{phrases.clearDates}
</span>
<CloseButton />
</button>
}
Expand Down
2 changes: 2 additions & 0 deletions src/components/DateRangePickerInputController.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ export default class DateRangePickerInputWithHandlers extends React.Component {
required,
phrases,
onArrowDown,
isFocused,
} = this.props;

const startDateString = this.getDateString(startDate);
Expand Down Expand Up @@ -246,6 +247,7 @@ export default class DateRangePickerInputWithHandlers extends React.Component {
onClearDates={this.clearDates}
screenReaderMessage={screenReaderMessage}
onArrowDown={onArrowDown}
isFocused={isFocused}
/>
);
}
Expand Down
Loading

0 comments on commit 3cc2495

Please sign in to comment.