diff --git a/src/date_utils.js b/src/date_utils.js index af2f91fe4..8c305c00b 100644 --- a/src/date_utils.js +++ b/src/date_utils.js @@ -6,12 +6,14 @@ import addHours from "date-fns/addHours"; import addDays from "date-fns/addDays"; import addWeeks from "date-fns/addWeeks"; import addMonths from "date-fns/addMonths"; +import addQuarters from "date-fns/addQuarters"; import addYears from "date-fns/addYears"; import subMinutes from "date-fns/subMinutes"; import subHours from "date-fns/subHours"; import subDays from "date-fns/subDays"; import subWeeks from "date-fns/subWeeks"; import subMonths from "date-fns/subMonths"; +import subQuarters from "date-fns/subQuarters"; import subYears from "date-fns/subYears"; import getSeconds from "date-fns/getSeconds"; import getMinutes from "date-fns/getMinutes"; @@ -265,7 +267,7 @@ export function getEndOfMonth(date) { // *** Addition *** -export { addMinutes, addDays, addWeeks, addMonths, addYears }; +export { addMinutes, addDays, addWeeks, addMonths, addQuarters, addYears }; // *** Subtraction *** @@ -276,6 +278,7 @@ export { subDays, subWeeks, subMonths, + subQuarters, subYears, }; @@ -377,7 +380,9 @@ export function getLocaleObject(localeSpec) { } export function getFormattedWeekdayInLocale(date, formatFunc, locale) { - return typeof formatFunc === "function" ? formatFunc(date, locale) : formatDate(date, "EEEE", locale); + return typeof formatFunc === "function" + ? formatFunc(date, locale) + : formatDate(date, "EEEE", locale); } export function getWeekdayMinInLocale(date, locale) { diff --git a/src/month.jsx b/src/month.jsx index 2ded5e45f..62b37746a 100644 --- a/src/month.jsx +++ b/src/month.jsx @@ -74,6 +74,7 @@ export default class Month extends React.Component { }; MONTH_REFS = [...Array(12)].map(() => React.createRef()); + QUARTER_REFS = [...Array(4)].map(() => React.createRef()); isDisabled = (date) => utils.isDayDisabled(date, this.props); @@ -141,6 +142,10 @@ export default class Month extends React.Component { utils.getYear(day) === utils.getYear(utils.newDate()) && m === utils.getMonth(utils.newDate()); + isCurrentQuarter = (day, q) => + utils.getYear(day) === utils.getYear(utils.newDate()) && + q === utils.getQuarter(utils.newDate()); + isSelectedMonth = (day, m, selected) => utils.getMonth(day) === m && utils.getYear(day) === utils.getYear(selected); @@ -277,6 +282,37 @@ export default class Month extends React.Component { ); }; + handleQuarterNavigation = (newQuarter, newDate) => { + if (this.isDisabled(newDate) || this.isExcluded(newDate)) return; + this.props.setPreSelection(newDate); + this.QUARTER_REFS[newQuarter - 1].current && + this.QUARTER_REFS[newQuarter - 1].current.focus(); + }; + + onQuarterKeyDown = (event, quarter) => { + const eventKey = event.key; + if (!this.props.disabledKeyboardNavigation) { + switch (eventKey) { + case "Enter": + this.onQuarterClick(event, quarter); + this.props.setPreSelection(this.props.selected); + break; + case "ArrowRight": + this.handleQuarterNavigation( + quarter === 4 ? 1 : quarter + 1, + utils.addQuarters(this.props.preSelection, 1) + ); + break; + case "ArrowLeft": + this.handleQuarterNavigation( + quarter === 1 ? 4 : quarter - 1, + utils.subQuarters(this.props.preSelection, 1) + ); + break; + } + } + }; + getMonthClassNames = (m) => { const { day, @@ -327,6 +363,16 @@ export default class Month extends React.Component { return tabIndex; }; + getQuarterTabIndex = (q) => { + const preSelectedQuarter = utils.getQuarter(this.props.preSelection); + const tabIndex = + !this.props.disabledKeyboardNavigation && q === preSelectedQuarter + ? "0" + : "-1"; + + return tabIndex; + }; + getAriaLabel = (month) => { const { chooseDayAriaLabelPrefix = "Choose", @@ -344,7 +390,15 @@ export default class Month extends React.Component { }; getQuarterClassNames = (q) => { - const { day, startDate, endDate, selected, minDate, maxDate } = this.props; + const { + day, + startDate, + endDate, + selected, + minDate, + maxDate, + preSelection, + } = this.props; return classnames( "react-datepicker__quarter-text", `react-datepicker__quarter-${q}`, @@ -357,6 +411,8 @@ export default class Month extends React.Component { q, selected ), + "react-datepicker__quarter-text--keyboard-selected": + utils.getQuarter(preSelection) === q, "react-datepicker__quarter--in-range": utils.isQuarterInRange( startDate, endDate, @@ -438,12 +494,18 @@ export default class Month extends React.Component { {quarters.map((q, j) => (