Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

a11y(DatePicker): move year and month selects from caption to navbar (fixes tab order and a11y failure) #6025

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
4984ec8
fix(DatePicker): move year and month selects from caption to navbar
bvandercar-vt Mar 15, 2023
e78b1fd
lint: fix prop order
bvandercar-vt Mar 15, 2023
277dc24
fix test titles
bvandercar-vt Mar 15, 2023
2627884
fix test
bvandercar-vt Mar 15, 2023
0e344e9
add screanreader-visible date to datepicker caption
bvandercar-vt Mar 16, 2023
97fc534
fix prop order css
bvandercar-vt Mar 16, 2023
4893106
Merge branch 'develop' into bvandercar/datepicker/move-month-year-sel…
bvandercar-vt Mar 20, 2023
fa5ab8e
move screenreader-only class to mixins
bvandercar-vt Mar 23, 2023
8722217
Merge branch 'develop' into bvandercar/datepicker/move-month-year-sel…
bvandercar-vt Mar 24, 2023
e196712
rename constant and class
bvandercar-vt Mar 24, 2023
4ab46ba
Merge branch 'develop' into bvandercar/datepicker/move-month-year-sel…
bvandercar-vt Apr 4, 2023
33fe272
Merge branch 'develop' into bvandercar/datepicker/move-month-year-sel…
bvandercar-vt Apr 18, 2023
f3ad566
Merge branch 'develop' into bvandercar/datepicker/move-month-year-sel…
bvandercar-vt Apr 18, 2023
174338e
Merge branch 'develop' into bvandercar/datepicker/move-month-year-sel…
bvandercar-vt Apr 18, 2023
fff7496
Merge branch 'develop' into bvandercar/datepicker/move-month-year-sel…
bvandercar-vt Apr 18, 2023
110dacf
remove caption, useless
bvandercar-vt Apr 18, 2023
8ba49e7
remove unnneeded import
bvandercar-vt Apr 18, 2023
efb67ed
mvoe to within
bvandercar-vt Apr 18, 2023
7b791a1
fix whitepsace
bvandercar-vt Apr 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/core/src/common/_mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@ $pt-dark-intent-text-colors: (
-moz-outline-radius: 6px;
}

@mixin screenreader-only() {
// reference: https://tailwindcss.com/docs/screen-readers
border-width: 0;
clip: rect(0, 0, 0, 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
white-space: nowrap;
width: 1px;
}

@function border-shadow($alpha, $color: $black, $size: 1px) {
@return 0 0 0 $size rgba($color, $alpha);
}
Expand Down
29 changes: 16 additions & 13 deletions packages/datetime/src/_datepicker.scss
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ $header-margin: ($header-height - $pt-input-height) * 0.5 !default;

.DayPicker-Caption {
display: table-caption;
visibility: hidden;
}

.DayPicker-Weekdays {
Expand Down Expand Up @@ -149,10 +150,9 @@ $header-margin: ($header-height - $pt-input-height) * 0.5 !default;
align-items: center;
display: flex;
height: $pt-button-height;
left: 0;
position: absolute;
right: 0;
top: 0;
justify-content: center;
margin-bottom: 5px;
position: relative;

> .DayPicker-NavButton--prev {
margin-right: auto;
Expand All @@ -161,26 +161,28 @@ $header-margin: ($header-height - $pt-input-height) * 0.5 !default;
> .DayPicker-NavButton--next {
margin-left: auto;
}
}

.#{$ns}-datepicker-caption {
@include pt-flex-container(row, $fill: ":first-child");
justify-content: space-between;
margin: 0 ($pt-button-height - $datepicker-padding) $datepicker-padding;
.#{$ns}-datepicker-navbar-center {
// centers item regardless of DayPicker-NavButton present
position: absolute;
}

// HTMLSelect overrides for a narrower appearance
select {
font-weight: 600;
padding-left: $datepicker-padding;
padding-right: $pt-icon-size-standard;
padding-right: $pt-icon-size-standard + 2;

+ .#{$ns}-icon {
right: 2px;
}
}

+ .#{$ns}-divider {
margin: 0;
// bottom border divider of navbar
.#{$ns}-divider {
position: absolute;
bottom: calc(0 - #{$datepicker-padding * 2});
width: calc(100% - #{$datepicker-padding * 2});
}
}

Expand All @@ -193,7 +195,7 @@ $header-margin: ($header-height - $pt-input-height) * 0.5 !default;
min-width: 60px;
}

.#{$ns}-datepicker-caption-measure {
.#{$ns}-datepicker-month-select-measure {
font-weight: 600;
padding-left: $datepicker-padding;
}
Expand Down Expand Up @@ -277,3 +279,4 @@ $header-margin: ($header-height - $pt-input-height) * 0.5 !default;
margin: $datepicker-padding 0;
}
}

6 changes: 2 additions & 4 deletions packages/datetime/src/common/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ export const DATEINPUT = `${NS}-dateinput`;
export const DATEINPUT_POPOVER = `${DATEINPUT}-popover`;

export const DATEPICKER = `${NS}-datepicker`;
export const DATEPICKER_CAPTION = `${DATEPICKER}-caption`;
export const DATEPICKER_CAPTION_CARET = `${DATEPICKER_CAPTION}-caret`;
export const DATEPICKER_CAPTION_MEASURE = `${DATEPICKER_CAPTION}-measure`;
export const DATEPICKER_CAPTION_SELECT = `${DATEPICKER_CAPTION}-select`;
export const DATEPICKER_CONTENT = `${DATEPICKER}-content`;
export const DATEPICKER_DAY = "DayPicker-Day";
export const DATEPICKER_DAY_DISABLED = `${DATEPICKER_DAY}--disabled`;
Expand All @@ -35,8 +31,10 @@ export const DATEPICKER_DAY_IS_TODAY = `${DATEPICKER_DAY}--isToday`;
export const DATEPICKER_DAY_WRAPPER = `${DATEPICKER}-day-wrapper`;
export const DATEPICKER_FOOTER = `${DATEPICKER}-footer`;
export const DATEPICKER_MONTH_SELECT = `${DATEPICKER}-month-select`;
export const DATEPICKER_MONTH_SELECT_MEASURE = `${DATEPICKER_MONTH_SELECT}-measure`;
export const DATEPICKER_YEAR_SELECT = `${DATEPICKER}-year-select`;
export const DATEPICKER_NAVBAR = `${DATEPICKER}-navbar`;
export const DATEPICKER_NAVBAR_CENTER = `${DATEPICKER_NAVBAR}-center`;
export const DATEPICKER_NAVBUTTON = `DayPicker-NavButton`;
export const DATEPICKER_TIMEPICKER_WRAPPER = `${DATEPICKER}-timepicker-wrapper`;

Expand Down
28 changes: 13 additions & 15 deletions packages/datetime/src/datePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@

import classNames from "classnames";
import * as React from "react";
import DayPicker, { CaptionElementProps, DayModifiers, NavbarElementProps } from "react-day-picker";
import DayPicker, { DayModifiers, NavbarElementProps } from "react-day-picker";

import { AbstractPureComponent2, Button, DISPLAYNAME_PREFIX, Divider, Props } from "@blueprintjs/core";

import * as Classes from "./common/classes";
import * as DateUtils from "./common/dateUtils";
import * as Errors from "./common/errors";
import { DatePickerCaption } from "./datePickerCaption";
import { DatePickerBaseProps, getDefaultMaxDate, getDefaultMinDate } from "./datePickerCore";
import { DatePickerMonthYearSelect } from "./datePickerMonthYearSelect";
import { DatePickerNavbar } from "./datePickerNavbar";
import { DatePickerShortcut, DateRangeShortcut, Shortcuts } from "./shortcuts";
import { TimePicker } from "./timePicker";
Expand Down Expand Up @@ -163,7 +163,7 @@ export class DatePicker extends AbstractPureComponent2<DatePickerProps, IDatePic
modifiers={this.getDatePickerModifiers()}
{...dayPickerProps}
canChangeMonth={true}
captionElement={this.renderCaption}
captionElement={<></>}
navbarElement={this.renderNavbar}
disabledDays={this.getDisabledDaysModifier()}
fromMonth={minDate}
Expand Down Expand Up @@ -255,18 +255,16 @@ export class DatePicker extends AbstractPureComponent2<DatePickerProps, IDatePic
return Array.isArray(disabledDays) ? [this.disabledDays, ...disabledDays] : [this.disabledDays, disabledDays];
};

private renderCaption = (props: CaptionElementProps) => (
<DatePickerCaption
{...props}
maxDate={this.props.maxDate}
minDate={this.props.minDate}
onDateChange={this.handleMonthChange}
reverseMonthAndYearMenus={this.props.reverseMonthAndYearMenus}
/>
);

private renderNavbar = (props: NavbarElementProps) => (
<DatePickerNavbar {...props} maxDate={this.props.maxDate} minDate={this.props.minDate} />
private renderNavbar = (navbarProps: NavbarElementProps) => (
<DatePickerNavbar {...navbarProps} maxDate={this.props.maxDate} minDate={this.props.minDate}>
<DatePickerMonthYearSelect
{...navbarProps}
onDateChange={this.handleMonthChange}
reverseMonthAndYearMenus={this.props.reverseMonthAndYearMenus}
maxDate={this.props.maxDate}
minDate={this.props.minDate}
/>
</DatePickerNavbar>
);

private renderOptionsBar() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,34 @@
*/

import * as React from "react";
import { CaptionElementProps } from "react-day-picker";
import { NavbarElementProps } from "react-day-picker";

import { AbstractPureComponent2, Divider, HTMLSelect, IconSize, OptionProps } from "@blueprintjs/core";
import { AbstractPureComponent2, HTMLSelect, IconSize, OptionProps } from "@blueprintjs/core";

import * as Classes from "./common/classes";
import { clone } from "./common/dateUtils";
import { measureTextWidth } from "./common/utils";

export interface IDatePickerCaptionProps extends CaptionElementProps {
export interface IDatePickerMonthYearSelectProps extends Pick<NavbarElementProps, "month" | "locale" | "localeUtils"> {
maxDate: Date;
minDate: Date;
months?: string[];
onMonthChange?: (month: number) => void;
onYearChange?: (year: number) => void;
/** Callback invoked when the month or year `<select>` is changed. */
onDateChange?: (date: Date) => void;
reverseMonthAndYearMenus?: boolean;
}

export interface IDatePickerCaptionState {
export interface IDatePickerMonthYearSelectState {
monthRightOffset: number;
}

export class DatePickerCaption extends AbstractPureComponent2<IDatePickerCaptionProps, IDatePickerCaptionState> {
public state: IDatePickerCaptionState = { monthRightOffset: 0 };
export class DatePickerMonthYearSelect extends AbstractPureComponent2<
IDatePickerMonthYearSelectProps,
IDatePickerMonthYearSelectState
> {
public state: IDatePickerMonthYearSelectState = { monthRightOffset: 0 };

private containerElement: HTMLElement;

Expand All @@ -49,7 +53,14 @@ export class DatePickerCaption extends AbstractPureComponent2<IDatePickerCaption
private handleYearSelectChange = this.dateChangeHandler((d, year) => d.setFullYear(year), this.props.onYearChange);

public render() {
const { date, locale, localeUtils, minDate, maxDate, months = localeUtils.getMonths(locale) } = this.props;
const {
month: date,
locale,
localeUtils,
minDate,
maxDate,
months = localeUtils.getMonths(locale),
} = this.props;
const minYear = minDate.getFullYear();
const maxYear = maxDate.getFullYear();
const displayMonth = date.getMonth();
Expand Down Expand Up @@ -101,14 +112,7 @@ export class DatePickerCaption extends AbstractPureComponent2<IDatePickerCaption
? [yearSelect, monthSelect]
: [monthSelect, yearSelect];

return (
<div className={this.props.classNames.caption}>
<div className={Classes.DATEPICKER_CAPTION} ref={ref => (this.containerElement = ref)}>
{orderedSelects}
</div>
<Divider />
</div>
);
return <div ref={ref => (this.containerElement = ref)}>{orderedSelects}</div>;
}

public componentDidMount() {
Expand All @@ -123,7 +127,7 @@ export class DatePickerCaption extends AbstractPureComponent2<IDatePickerCaption
// measure width of text as rendered inside our container element.
const monthTextWidth = measureTextWidth(
this.displayedMonthText,
Classes.DATEPICKER_CAPTION_MEASURE,
Classes.DATEPICKER_MONTH_SELECT_MEASURE,
this.containerElement,
);
const monthSelectWidth =
Expand All @@ -139,7 +143,7 @@ export class DatePickerCaption extends AbstractPureComponent2<IDatePickerCaption
if (isNaN(value)) {
return;
}
const newDate = clone(this.props.date);
const newDate = clone(this.props.month);
updater(newDate, value);
this.props.onDateChange?.(newDate);
handler?.(value);
Expand Down
7 changes: 6 additions & 1 deletion packages/datetime/src/datePickerNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import classNames from "classnames";
import * as React from "react";
import { NavbarElementProps } from "react-day-picker";

import { Button } from "@blueprintjs/core";
import { Button, Divider } from "@blueprintjs/core";

import * as Classes from "./common/classes";
import { areSameMonth } from "./common/dateUtils";
Expand All @@ -29,6 +29,9 @@ export interface IDatePickerNavbarProps extends NavbarElementProps {

hideLeftNavButton?: boolean;
hideRightNavButton?: boolean;

/** Placed at center */
children?: React.ReactNode;
}

export class DatePickerNavbar extends React.PureComponent<IDatePickerNavbarProps> {
Expand All @@ -47,6 +50,7 @@ export class DatePickerNavbar extends React.PureComponent<IDatePickerNavbarProps
onClick={this.handlePreviousClick}
/>
)}
{this.props.children && <div className={Classes.DATEPICKER_NAVBAR_CENTER}>{this.props.children}</div>}
{this.props.hideRightNavButton || (
<Button
aria-label="Go to next month"
Expand All @@ -57,6 +61,7 @@ export class DatePickerNavbar extends React.PureComponent<IDatePickerNavbarProps
onClick={this.handleNextClick}
/>
)}
<Divider />
</div>
);
}
Expand Down
Loading