Skip to content

Commit

Permalink
Merge pull request #12 from OutSystems/ROU-3947
Browse files Browse the repository at this point in the history
Improve MonthPicker plugin A11Y
  • Loading branch information
BenOsodrac authored Jan 12, 2024
2 parents 3187879 + 6bea76d commit 04bb9ff
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 71 deletions.
149 changes: 85 additions & 64 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ function FlatpickrInstance(
},
generateUniqueId() {
return Math.random().toString(36);
}
},
};
}

Expand Down Expand Up @@ -167,7 +167,6 @@ function FlatpickrInstance(
(e: KeyboardEvent) => {
if (e.key === "Tab") {
if (e.shiftKey) {
//shift+tab pressed
return;
} else {
_predictableTopElement.focus();
Expand Down Expand Up @@ -231,7 +230,7 @@ function FlatpickrInstance(
if (self.selectedDates.length === 0) {
const defaultDate =
self.config.minDate === undefined ||
compareDates(new Date(), self.config.minDate) >= 0
compareDates(new Date(), self.config.minDate) >= 0
? new Date()
: new Date(self.config.minDate.getTime());

Expand Down Expand Up @@ -299,15 +298,15 @@ function FlatpickrInstance(
self.minDateHasTime &&
self.latestSelectedDateObj &&
compareDates(self.latestSelectedDateObj, self.config.minDate, true) ===
0);
0);

const limitMaxHours =
self.config.maxTime !== undefined ||
(self.config.maxDate &&
self.maxDateHasTime &&
self.latestSelectedDateObj &&
compareDates(self.latestSelectedDateObj, self.config.maxDate, true) ===
0);
0);

if (
self.config.maxTime !== undefined &&
Expand Down Expand Up @@ -462,6 +461,8 @@ function FlatpickrInstance(
self.open();
if (self.config.noCalendar || self.isMobile) {
self.hourElement?.focus();
} else if (self.loadedPlugins.indexOf("monthSelect") !== -1) {
focusOnAvailableMonth();
} else {
focusOnDay(getFirstAvailableDay(1), 0);
}
Expand Down Expand Up @@ -591,9 +592,9 @@ function FlatpickrInstance(
jumpDate !== undefined
? self.parseDate(jumpDate)
: self.latestSelectedDateObj ||
(self.config.minDate && self.config.minDate > self.now
? self.config.minDate
: self.config.maxDate && self.config.maxDate < self.now
(self.config.minDate && self.config.minDate > self.now
? self.config.minDate
: self.config.maxDate && self.config.maxDate < self.now
? self.config.maxDate
: self.now);

Expand Down Expand Up @@ -664,11 +665,12 @@ function FlatpickrInstance(
"div",
"flatpickr-calendar"
);
self.calendarContainer.id = 'flatpickr-calendar-' + self.utils.generateUniqueId();
self.calendarContainer.role = 'dialog';
self.calendarContainer.ariaModal = 'true';
self.calendarContainer.id =
"flatpickr-calendar-" + self.utils.generateUniqueId();
self.calendarContainer.role = "dialog";
self.calendarContainer.ariaModal = "true";
self.calendarContainer.ariaLabel = self.l10n.ariaLabelCalendar;
self.altInput?.setAttribute('aria-controls', self.calendarContainer.id);
self.altInput?.setAttribute("aria-controls", self.calendarContainer.id);
self.calendarContainer.tabIndex = -1;

if (!self.config.noCalendar) {
Expand Down Expand Up @@ -810,14 +812,14 @@ function FlatpickrInstance(
dayElement,
"startRange",
self.selectedDates[0] &&
compareDates(date, self.selectedDates[0], true) === 0
compareDates(date, self.selectedDates[0], true) === 0
);

toggleClass(
dayElement,
"endRange",
self.selectedDates[1] &&
compareDates(date, self.selectedDates[1], true) === 0
compareDates(date, self.selectedDates[1], true) === 0
);

if (className === "nextMonthDay") dayElement.classList.add("inRange");
Expand Down Expand Up @@ -890,8 +892,8 @@ function FlatpickrInstance(
givenMonth - self.currentMonth === m
? current.$i + delta
: delta < 0
? month.children.length - 1
: 0;
? month.children.length - 1
: 0;
const numMonthDays = month.children.length;

for (
Expand Down Expand Up @@ -922,12 +924,12 @@ function FlatpickrInstance(
current !== undefined
? current
: dayFocused
? (activeElement as DayElement)
: self.selectedDateElem !== undefined && isInView(self.selectedDateElem)
? self.selectedDateElem
: self.todayDateElem !== undefined && isInView(self.todayDateElem)
? self.todayDateElem
: getFirstAvailableDay(offset > 0 ? 1 : -1);
? (activeElement as DayElement)
: self.selectedDateElem !== undefined && isInView(self.selectedDateElem)
? self.selectedDateElem
: self.todayDateElem !== undefined && isInView(self.todayDateElem)
? self.todayDateElem
: getFirstAvailableDay(offset > 0 ? 1 : -1);

if (startElem === undefined) {
self._input.focus();
Expand Down Expand Up @@ -1169,7 +1171,7 @@ function FlatpickrInstance(
self.monthElements = [];
}

for (let m = self.config.showMonths; m--;) {
for (let m = self.config.showMonths; m--; ) {
const month = buildMonth();
self.yearElements.push(month.yearElement);
self.monthElements.push(month.monthElement);
Expand Down Expand Up @@ -1261,8 +1263,8 @@ function FlatpickrInstance(
self.latestSelectedDateObj
? self.latestSelectedDateObj.getHours()
: self.config.time_24hr
? defaults.hours
: military2ampm(defaults.hours)
? defaults.hours
: military2ampm(defaults.hours)
);

self.minuteElement.value = pad(
Expand Down Expand Up @@ -1325,11 +1327,11 @@ function FlatpickrInstance(
"span",
"flatpickr-am-pm",
self.l10n.amPM[
int(
(self.latestSelectedDateObj
? self.hourElement.value
: self.config.defaultHour) > 11
)
int(
(self.latestSelectedDateObj
? self.hourElement.value
: self.config.defaultHour) > 11
)
]
);
self.amPM.title = self.l10n.toggleTitle;
Expand All @@ -1349,7 +1351,7 @@ function FlatpickrInstance(
);
else clearNode(self.weekdayContainer);

for (let i = self.config.showMonths; i--;) {
for (let i = self.config.showMonths; i--; ) {
const container = createElement<HTMLDivElement>(
"div",
"flatpickr-weekdaycontainer"
Expand Down Expand Up @@ -1378,7 +1380,7 @@ function FlatpickrInstance(
];
}

for (let i = self.config.showMonths; i--;) {
for (let i = self.config.showMonths; i--; ) {
self.weekdayContainer.children[i].innerHTML = `
<span class='flatpickr-weekday'>
${weekdays.join("</span><span class='flatpickr-weekday'>")}
Expand Down Expand Up @@ -1480,7 +1482,7 @@ function FlatpickrInstance(
function destroy() {
if (self.config !== undefined) triggerEvent("onDestroy");

for (let i = self._handlers.length; i--;) {
for (let i = self._handlers.length; i--; ) {
self._handlers[i].remove();
}

Expand Down Expand Up @@ -1550,7 +1552,7 @@ function FlatpickrInstance(
] as (keyof Instance)[]).forEach((k) => {
try {
delete self[k as keyof Instance];
} catch (_) { }
} catch (_) {}
});
}

Expand Down Expand Up @@ -1907,8 +1909,8 @@ function FlatpickrInstance(
return;

const hoverDate = elem
? elem.dateObj.getTime()
: (self.days.firstElementChild as DayElement).dateObj.getTime(),
? elem.dateObj.getTime()
: (self.days.firstElementChild as DayElement).dateObj.getTime(),
initialDate = (self.parseDate(
self.selectedDates[0],
undefined,
Expand Down Expand Up @@ -2082,7 +2084,7 @@ function FlatpickrInstance(

const inverseDateObj =
self.config[
`_${type === "min" ? "max" : "min"}Date` as "_minDate" | "_maxDate"
`_${type === "min" ? "max" : "min"}Date` as "_minDate" | "_maxDate"
];

if (dateObj !== undefined) {
Expand Down Expand Up @@ -2278,16 +2280,17 @@ function FlatpickrInstance(
...(typeof self.config.locale === "object"
? self.config.locale
: self.config.locale !== "default"
? flatpickr.l10ns[self.config.locale as LocaleKey]
: undefined),
? flatpickr.l10ns[self.config.locale as LocaleKey]
: undefined),
};

tokenRegex.D = `(${self.l10n.weekdays.shorthand.join("|")})`;
tokenRegex.l = `(${self.l10n.weekdays.longhand.join("|")})`;
tokenRegex.M = `(${self.l10n.months.shorthand.join("|")})`;
tokenRegex.F = `(${self.l10n.months.longhand.join("|")})`;
tokenRegex.K = `(${self.l10n.amPM[0]}|${self.l10n.amPM[1]
}|${self.l10n.amPM[0].toLowerCase()}|${self.l10n.amPM[1].toLowerCase()})`;
tokenRegex.K = `(${self.l10n.amPM[0]}|${
self.l10n.amPM[1]
}|${self.l10n.amPM[0].toLowerCase()}|${self.l10n.amPM[1].toLowerCase()})`;

const userConfig = {
...instanceConfig,
Expand Down Expand Up @@ -2315,10 +2318,10 @@ function FlatpickrInstance(
const positionElement = customPositionElement || self._positionElement;

const calendarHeight = Array.prototype.reduce.call(
self.calendarContainer.children,
((acc: number, child: HTMLElement) => acc + child.offsetHeight) as any,
0
) as number,
self.calendarContainer.children,
((acc: number, child: HTMLElement) => acc + child.offsetHeight) as any,
0
) as number,
calendarWidth = self.calendarContainer.offsetWidth,
configPos = self.config.position.split(" "),
configPosVertical = configPos[0],
Expand Down Expand Up @@ -2464,7 +2467,7 @@ function FlatpickrInstance(
const shouldChangeMonth =
(selectedDate.getMonth() < self.currentMonth ||
selectedDate.getMonth() >
self.currentMonth + self.config.showMonths - 1) &&
self.currentMonth + self.config.showMonths - 1) &&
self.config.mode !== "range";

self.selectedDateElem = target;
Expand Down Expand Up @@ -2619,8 +2622,8 @@ function FlatpickrInstance(
self.selectedDates = (self.config.allowInvalidPreload
? dates
: dates.filter(
(d) => d instanceof Date && isEnabled(d, false)
)) as Date[];
(d) => d instanceof Date && isEnabled(d, false)
)) as Date[];

if (self.config.mode === "range")
self.selectedDates.sort((a, b) => a.getTime() - b.getTime());
Expand Down Expand Up @@ -2693,8 +2696,8 @@ function FlatpickrInstance(
self.config.defaultDate ||
((self.input.nodeName === "INPUT" ||
self.input.nodeName === "TEXTAREA") &&
self.input.placeholder &&
self.input.value === self.input.placeholder
self.input.placeholder &&
self.input.value === self.input.placeholder
? null
: self.input.value);

Expand All @@ -2705,11 +2708,11 @@ function FlatpickrInstance(
? self.selectedDates[0]
: self.config.minDate &&
self.config.minDate.getTime() > self.now.getTime()
? self.config.minDate
: self.config.maxDate &&
self.config.maxDate.getTime() < self.now.getTime()
? self.config.maxDate
: self.now;
? self.config.minDate
: self.config.maxDate &&
self.config.maxDate.getTime() < self.now.getTime()
? self.config.maxDate
: self.now;

self.currentYear = self._initialDate.getFullYear();
self.currentMonth = self._initialDate.getMonth();
Expand Down Expand Up @@ -2766,10 +2769,10 @@ function FlatpickrInstance(
self.altInput.type = "text";

// add accessibility attributes
self.altInput.role = 'combobox';
self.altInput.ariaHasPopup = 'true';
self.altInput.ariaAutoComplete = 'none';
self.altInput.ariaExpanded = 'false';
self.altInput.role = "combobox";
self.altInput.ariaHasPopup = "true";
self.altInput.ariaAutoComplete = "none";
self.altInput.ariaExpanded = "false";

self.input.setAttribute("type", "hidden");

Expand Down Expand Up @@ -2811,8 +2814,8 @@ function FlatpickrInstance(
inputType === "datetime-local"
? "Y-m-d\\TH:i:S"
: inputType === "date"
? "Y-m-d"
: "H:i:S";
? "Y-m-d"
: "H:i:S";

if (self.selectedDates.length > 0) {
self.mobileInput.defaultValue = self.mobileInput.value = self.formatDate(
Expand All @@ -2839,7 +2842,7 @@ function FlatpickrInstance(
self.mobileInput,
self.input.nextSibling
);
} catch { }
} catch {}

bind(self.mobileInput, "change", (e: KeyboardEvent) => {
self.setDate(
Expand Down Expand Up @@ -2984,8 +2987,25 @@ function FlatpickrInstance(
}

/**
* Method to change the month view when using keyboard on next/prev arrows
*/
* Method to focus on the available month
*/
function focusOnAvailableMonth() {
// Get selected month, first try selected, then get the first one
const targetMonth =
(self.calendarContainer?.querySelector(
".flatpickr-monthSelect-month.selected"
) as HTMLElement) ||
(self.calendarContainer?.querySelector(
".flatpickr-monthSelect-month"
) as HTMLElement);

// Focus on target month
targetMonth?.focus();
}

/**
* Method to change the month view when using keyboard on next/prev arrows
*/
function onMonthKeydown(e: KeyboardEvent) {
const eventTarget = getEventTarget(e);
const isPrevMonth = self.prevMonthNav.contains(eventTarget as Node);
Expand All @@ -2994,6 +3014,7 @@ function FlatpickrInstance(
if (isPrevMonth || isNextMonth) {
if (e.key === "Enter" || e.key === " ") {
changeMonth(isPrevMonth ? -1 : 1);

return;
}

Expand Down
Loading

0 comments on commit 04bb9ff

Please sign in to comment.