Skip to content

Commit

Permalink
fix(datepicker): fix onBlur, tabIndex and a11y issues (#511)
Browse files Browse the repository at this point in the history
* feat(datepicker): support tabIndex prop

* fix(datepicker): fire onBlur when leaving input

* feat(a11y): make dates tabbable and translate aria-labels

* fix(a11y): show calendar when input is focused

* ci(GitHub): change name of semantic-release step
  • Loading branch information
arthurdenner committed Jan 29, 2021
1 parent 61bffb1 commit 6cd97ef
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 30 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
run: yarn validate
- name: Upload test reports
uses: codecov/codecov-action@v1
- name: Semantic Release
- name: Run semantic-release
uses: cycjimmy/semantic-release-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
5 changes: 3 additions & 2 deletions src/__tests__/datepicker.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { fireEvent } from '@testing-library/react';
import { fireEvent, waitFor } from '@testing-library/react';
import localeEn from '../locales/en-US.json';
import localePt from '../locales/pt-BR.json';
import { getShortDate } from '../utils';
Expand Down Expand Up @@ -220,7 +220,8 @@ describe('Basic datepicker', () => {
});

fireEvent.click(getByLabelText('Click me'));
expect(getByText('Today')).toBeTruthy();

waitFor(() => expect(getByText('Today')).toBeTruthy());
});

describe('clearOnSameDateClick', () => {
Expand Down
1 change: 1 addition & 0 deletions src/__tests__/usecases.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ it('onChange is fired when invalid date is typed', () => {
openDatePicker();
fireEvent.click(screen.getByText('Today'));

expect(datePickerInput).toHaveFocus();
expect(onChange).toHaveBeenCalledTimes(1);
expect(onBlur).toHaveBeenCalledTimes(1);

Expand Down
2 changes: 1 addition & 1 deletion src/components/calendar/calendar.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
text-align: center;
display: grid;
grid-gap: 1px;
grid-template-columns: repeat(7, 2.2rem);
grid-template-columns: repeat(7, minmax(2.2rem, 1fr));
background-color: rgba(0, 0, 0, 0.1);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 0.28571429rem;
Expand Down
23 changes: 19 additions & 4 deletions src/components/calendar/calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,21 @@ const Calendar: React.FC<CalendarProps> = ({
icon="angle double left"
inverted={inverted}
title={previousYear}
{...getBackProps({ calendars, offset: 12 })}
{...getBackProps({
calendars,
'aria-label': previousYear,
offset: 12,
})}
/>
<Button
icon="angle left"
inverted={inverted}
style={{ marginRight: 0 }}
title={previousMonth}
{...getBackProps({ calendars })}
{...getBackProps({
calendars,
'aria-label': previousMonth,
})}
/>
</Fragment>
)}
Expand All @@ -102,14 +109,21 @@ const Calendar: React.FC<CalendarProps> = ({
icon="angle right"
inverted={inverted}
title={nextMonth}
{...getForwardProps({ calendars })}
{...getForwardProps({
calendars,
'aria-label': nextMonth,
})}
/>
<Button
icon="angle double right"
inverted={inverted}
style={{ marginRight: 0 }}
title={nextYear}
{...getForwardProps({ calendars, offset: 12 })}
{...getForwardProps({
calendars,
'aria-label': nextYear,
offset: 12,
})}
/>
</Fragment>
)}
Expand All @@ -120,6 +134,7 @@ const Calendar: React.FC<CalendarProps> = ({
<CalendarCell
key={`${calendar.year}-${calendar.month}-${weekday}`}
inverted={inverted}
aria-label={weekday}
title={weekday}
>
{weekday.slice(0, 2)}
Expand Down
3 changes: 3 additions & 0 deletions src/components/cell/cell.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
padding: 5px 0;
height: 30px;
cursor: pointer;
border: none;
color: inherit;
font-family: inherit;
}

.clndr-cell.inverted {
Expand Down
38 changes: 25 additions & 13 deletions src/components/cell/cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type CalendarCellProps = {
};

const CalendarCell: React.FC<CalendarCellProps> = ({
children,
end,
hovered,
inRange,
Expand All @@ -28,19 +29,30 @@ const CalendarCell: React.FC<CalendarCellProps> = ({
start,
today,
...otherProps
}) => (
<span
className={cn('clndr-cell', {
inverted,
'clndr-cell-today': today,
'clndr-cell-disabled': !selectable,
'clndr-cell-other-month': nextMonth || prevMonth,
'clndr-cell-inrange': inRange,
'clndr-cell-selected': selected,
})}
{...otherProps}
/>
);
}) => {
const className = cn('clndr-cell', {
inverted,
'clndr-cell-today': today,
'clndr-cell-disabled': !selectable,
'clndr-cell-other-month': nextMonth || prevMonth,
'clndr-cell-inrange': inRange,
'clndr-cell-selected': selected,
});

if (!children || !selectable) {
return (
<span className={className} {...otherProps} tabIndex={children ? 0 : -1}>
{children}
</span>
);
}

return (
<button className={className} {...otherProps}>
{children}
</button>
);
};

CalendarCell.defaultProps = {
end: false,
Expand Down
6 changes: 3 additions & 3 deletions src/components/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const CustomInput = React.forwardRef<Input, InputProps>((props, ref) => {
isClearIconVisible,
label,
onClear,
onClick,
onFocus,
required,
value,
...rest
Expand All @@ -36,10 +36,10 @@ const CustomInput = React.forwardRef<Input, InputProps>((props, ref) => {
icon={icon}
isClearIconVisible={isClearIconVisible}
onClear={onClear}
onClick={onClick}
onClick={onFocus}
/>
}
onClick={onClick}
onFocus={onFocus}
value={value}
/>
</Form.Field>
Expand Down
7 changes: 6 additions & 1 deletion src/components/today-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ interface TodayButtonProps extends DateObj, ButtonProps {
const style: React.CSSProperties = { marginTop: 10 };

const TodayButton: React.FC<TodayButtonProps> = ({
'aria-label': ariaLabel,
children,
end,
hovered,
inRange,
Expand All @@ -24,13 +26,16 @@ const TodayButton: React.FC<TodayButtonProps> = ({
...otherProps
}) => (
<Button
aria-label={`${ariaLabel}, ${children}`}
className="clndr-button-today"
compact
data-testid="datepicker-today-button"
fluid
style={style}
{...otherProps}
/>
>
{children}
</Button>
);

export default TodayButton;
15 changes: 10 additions & 5 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const semanticInputProps = [
'placeholder',
'required',
'size',
'tabIndex',
'transparent',
'readOnly',
];
Expand Down Expand Up @@ -233,8 +234,12 @@ class SemanticDatepicker extends React.Component<
};

focusOnInput = () => {
if (this.inputRef?.current?.focus) {
this.inputRef.current.focus();
if (this.inputRef?.current) {
// @ts-ignore
const { focus, inputRef } = this.inputRef.current;
if (document.activeElement !== inputRef.current) {
focus();
}
}
};

Expand Down Expand Up @@ -325,7 +330,7 @@ class SemanticDatepicker extends React.Component<
}

const newState = {
isVisible: keepOpenOnSelect,
isVisible: fromBlur || keepOpenOnSelect,
selectedDate: newDate,
selectedDateFormatted: formatSelectedDate(newDate, format),
typedValue: null,
Expand Down Expand Up @@ -462,10 +467,10 @@ class SemanticDatepicker extends React.Component<
<Input
{...this.inputProps}
isClearIconVisible={Boolean(clearable && selectedDateFormatted)}
onBlur={() => {}}
onBlur={this.handleBlur}
onChange={this.handleChange}
onClear={this.clearInput}
onClick={readOnly ? null : this.showCalendar}
onFocus={readOnly ? null : this.showCalendar}
onKeyDown={this.handleKeyDown}
readOnly={readOnly || datePickerOnly}
ref={this.inputRef}
Expand Down
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export type PickedFormInputProps = Pick<
| 'name'
| 'placeholder'
| 'size'
| 'tabIndex'
| 'transparent'
| 'readOnly'
>;
Expand Down

0 comments on commit 6cd97ef

Please sign in to comment.