Skip to content

Commit

Permalink
Added props for fully dynamic aria-labels (#2062)
Browse files Browse the repository at this point in the history
* Added props for fully dynamic aria-labels

* Fixed yarn lint error

* Revert "Fixed yarn lint error"

This reverts commit 430e659.

* Fixed yarn lint error
  • Loading branch information
oscarcarlstrom committed Feb 20, 2020
1 parent 1795d44 commit 3b720a3
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 16 deletions.
12 changes: 10 additions & 2 deletions src/calendar.jsx
Expand Up @@ -68,6 +68,10 @@ export default class Calendar extends React.Component {

static propTypes = {
adjustDateOnChange: PropTypes.bool,
previousMonthAriaLabel: PropTypes.string,
nextMonthAriaLabel: PropTypes.string,
previousYearAriaLabel: PropTypes.string,
nextYearAriaLabel: PropTypes.string,
className: PropTypes.string,
children: PropTypes.node,
container: PropTypes.func,
Expand Down Expand Up @@ -389,12 +393,14 @@ export default class Calendar extends React.Component {
const isForYear =
this.props.showMonthYearPicker || this.props.showQuarterYearPicker;

const { previousMonthAriaLabel = "Previous Month", previousYearAriaLabel = "Previous Year" } = this.props;

return (
<button
type="button"
className={classes.join(" ")}
onClick={clickHandler}
aria-label={isForYear ? "Previous Year" : "Previous Month"}
aria-label={isForYear ? previousYearAriaLabel : previousMonthAriaLabel}
>
{isForYear
? this.props.previousYearButtonLabel
Expand Down Expand Up @@ -455,12 +461,14 @@ export default class Calendar extends React.Component {
const isForYear =
this.props.showMonthYearPicker || this.props.showQuarterYearPicker;

const { nextMonthAriaLabel = "Previous Month", nextYearAriaLabel = "Previous Year" } = this.props;

return (
<button
type="button"
className={classes.join(" ")}
onClick={clickHandler}
aria-label={isForYear ? "Next Year" : "Next Month"}
aria-label={isForYear ? nextYearAriaLabel : nextMonthAriaLabel}
>
{isForYear
? this.props.nextYearButtonLabel
Expand Down
14 changes: 11 additions & 3 deletions src/day.jsx
Expand Up @@ -19,6 +19,8 @@ import {

export default class Day extends React.Component {
static propTypes = {
ariaLabelPrefixWhenEnabled: PropTypes.string,
ariaLabelPrefixWhenDisabled: PropTypes.string,
disabledKeyboardNavigation: PropTypes.bool,
day: PropTypes.instanceOf(Date).isRequired,
dayClassName: PropTypes.func,
Expand Down Expand Up @@ -237,9 +239,15 @@ export default class Day extends React.Component {
};

getAriaLabel = () => {
const { day } = this.props;
const prefix =
this.isDisabled() || this.isExcluded() ? "Not available" : "Choose";
const {
day,
ariaLabelPrefixWhenEnabled = "Choose",
ariaLabelPrefixWhenDisabled = "Not available"
} = this.props;

const prefix = this.isDisabled() || this.isExcluded()
? ariaLabelPrefixWhenDisabled
: ariaLabelPrefixWhenEnabled;

return `${prefix} ${formatDate(day, "PPPP")}`;
};
Expand Down
8 changes: 5 additions & 3 deletions src/index.jsx
Expand Up @@ -113,6 +113,7 @@ export default class DatePicker extends React.Component {
static propTypes = {
adjustDateOnChange: PropTypes.bool,
allowSameDay: PropTypes.bool,
ariaLabelClose: PropTypes.string,
ariaLabelledBy: PropTypes.string,
autoComplete: PropTypes.string,
autoFocus: PropTypes.bool,
Expand Down Expand Up @@ -834,14 +835,15 @@ export default class DatePicker extends React.Component {
};

renderClearButton = () => {
if (this.props.isClearable && this.props.selected != null) {
const { isClearable, selected, clearButtonTitle, ariaLabelClose = "Close" } = this.props;
if (isClearable && selected != null) {
return (
<button
type="button"
className="react-datepicker__close-icon"
aria-label="Close"
aria-label={ariaLabelClose}
onClick={this.onClearClick}
title={this.props.clearButtonTitle}
title={clearButtonTitle}
tabIndex={-1}
/>
);
Expand Down
5 changes: 3 additions & 2 deletions src/month.jsx
Expand Up @@ -8,6 +8,7 @@ const FIXED_HEIGHT_STANDARD_WEEK_COUNT = 6;

export default class Month extends React.Component {
static propTypes = {
ariaLabelPrefix: PropTypes.string,
disabledKeyboardNavigation: PropTypes.bool,
day: PropTypes.instanceOf(Date).isRequired,
dayClassName: PropTypes.func,
Expand Down Expand Up @@ -300,13 +301,13 @@ export default class Month extends React.Component {
};

render() {
const { showMonthYearPicker, showQuarterYearPicker } = this.props;
const { showMonthYearPicker, showQuarterYearPicker, day, ariaLabelPrefix = "month " } = this.props;
return (
<div
className={this.getClassNames()}
onMouseLeave={this.handleMouseLeave}
role="listbox"
aria-label={"month-" + utils.formatDate(this.props.day, "yyyy-MM")}
aria-label={`${ariaLabelPrefix} ${utils.formatDate(day, "yyyy-MM")}`}
>
{showMonthYearPicker
? this.renderMonths()
Expand Down
10 changes: 6 additions & 4 deletions src/week_number.jsx
Expand Up @@ -5,7 +5,8 @@ import classnames from "classnames";

export default class WeekNumber extends React.Component<{
weekNumber: number,
onClick?: Function
onClick?: Function,
ariaLabelPrefix?: string
}> {
static propTypes = {
weekNumber: PropTypes.number.isRequired,
Expand All @@ -19,17 +20,18 @@ export default class WeekNumber extends React.Component<{
};

render() {
const { weekNumber, ariaLabelPrefix = "week ", onClick } = this.props;
const weekNumberClasses = {
"react-datepicker__week-number": true,
"react-datepicker__week-number--clickable": !!this.props.onClick
"react-datepicker__week-number--clickable": !!onClick
};
return (
<div
className={classnames(weekNumberClasses)}
aria-label={`week-${this.props.weekNumber}`}
aria-label={`${ariaLabelPrefix} ${this.props.weekNumber}`}
onClick={this.handleClick}
>
{this.props.weekNumber}
{weekNumber}
</div>
);
}
Expand Down
54 changes: 54 additions & 0 deletions test/calendar_test.js
Expand Up @@ -1201,4 +1201,58 @@ describe("Calendar", function() {
assert.equal(ref, instance.containerRef.current);
});
});

it("should have a next-button with the provided aria-label for year", () => {
const ariaLabel = "A label in my native language for next year";
const shallowCalendar = mount(
<Calendar
nextYearAriaLabel={ariaLabel}
dateFormat={DATE_FORMAT}
onSelect={() => {}}
onClickOutside={() => {}}
showQuarterYearPicker
/>
);
expect(shallowCalendar.html().indexOf(`aria-label="${ariaLabel}"`)).not.equal(-1);
});

it("should have a previous-button with the provided aria-label for year", () => {
const ariaLabel = "A label in my native language for previous year";
const shallowCalendar = mount(
<Calendar
previousYearAriaLabel={ariaLabel}
dateFormat={DATE_FORMAT}
onSelect={() => {}}
onClickOutside={() => {}}
showQuarterYearPicker
/>
);
expect(shallowCalendar.html().indexOf(`aria-label="${ariaLabel}"`)).not.equal(-1);
});

it("should have a next-button with the provided aria-label for month", () => {
const ariaLabel = "A label in my native language for next month";
const shallowCalendar = mount(
<Calendar
nextMonthAriaLabel={ariaLabel}
dateFormat={DATE_FORMAT}
onSelect={() => {}}
onClickOutside={() => {}}
/>
);
expect(shallowCalendar.html().indexOf(`aria-label="${ariaLabel}"`)).not.equal(-1);
});

it("should have a previous-button with the provided aria-label for month", () => {
const ariaLabel = "A label in my native language for previous month";
const shallowCalendar = mount(
<Calendar
previousMonthAriaLabel={ariaLabel}
dateFormat={DATE_FORMAT}
onSelect={() => {}}
onClickOutside={() => {}}
/>
);
expect(shallowCalendar.html().indexOf(`aria-label="${ariaLabel}"`)).not.equal(-1);
});
});
16 changes: 16 additions & 0 deletions test/day_test.js
Expand Up @@ -507,6 +507,22 @@ describe("Day", () => {
});
});

describe("aria-label", () => {
const ariaLabelPrefixWhenEnabled = "A prefix in my native language desbribing that the date can be selected";
const ariaLabelPrefixWhenDisabled = "A prefix in my native language desbribing that the date can not be selected";

it("should have the correct provided prefix if date is not disabled", () => {
const shallowDay = renderDay(newDate(), { ariaLabelPrefixWhenEnabled: ariaLabelPrefixWhenEnabled });
expect(shallowDay.html().indexOf(`aria-label="${ariaLabelPrefixWhenEnabled}`)).not.equal(-1);
});

it("should have the correct provided prefix if date is disabled", () => {
const day = newDate();
const shallowDay = renderDay(day, { ariaLabelPrefixWhenDisabled: ariaLabelPrefixWhenDisabled, excludeDates: [day] });
expect(shallowDay.html().indexOf(`aria-label="${ariaLabelPrefixWhenDisabled}`)).not.equal(-1);
});
});

describe("click", () => {
var onClickCalled;

Expand Down
13 changes: 11 additions & 2 deletions test/month_test.js
Expand Up @@ -30,14 +30,23 @@ describe("Month", () => {
});

it("should have the month aria-label", () => {
const dateString = "2015-12";
const month = TestUtils.renderIntoDocument(
<Month day={utils.newDate("2015-12-01")} />
<Month day={utils.newDate(`${dateString}-01`)} />
);
const month_dom = TestUtils.findRenderedDOMComponentWithClass(
month,
"react-datepicker__month"
);
expect(month_dom.getAttribute("aria-label")).to.equal("month-2015-12");
expect(month_dom.getAttribute("aria-label")).to.contain(dateString);
});

it("should have an aria-label containing the provided prefix", () => {
const ariaLabelPrefix = "A prefix in my native language";
const shallowMonth = shallow(
<Month ariaLabelPrefix={ariaLabelPrefix} day={utils.newDate()} />
);
expect(shallowMonth.html().indexOf(`aria-label="${ariaLabelPrefix}`)).not.equal(-1);
});

it("should render all days of the month and some days in neighboring months", () => {
Expand Down
8 changes: 8 additions & 0 deletions test/week_number_test.js
Expand Up @@ -27,5 +27,13 @@ describe("WeekNumber", () => {
shallowWeekNumber.instance().handleClick({});
expect(onClick).to.have.property("callCount", 1);
});

it("should have an aria-label containing the provided prefix", () => {
const ariaLabelPrefix = "A prefix in my native language";
const shallowWeekNumber = shallow(
<WeekNumber day={1} ariaLabelPrefix={ariaLabelPrefix} />
);
expect(shallowWeekNumber.html().indexOf(`aria-label="${ariaLabelPrefix}`)).not.equal(-1);
});
});
});

0 comments on commit 3b720a3

Please sign in to comment.