Skip to content

fix(ui5-calendar): remove auto-focus logic in onAfterRendering() hook #12066

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

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions packages/main/cypress/specs/Calendar.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ describe("Calendar general interaction", () => {
cy.ui5CalendarGetDay("#calendar1", "974851200")
.realClick();

cy.focused().realPress("Tab");
cy.focused().realPress("Tab");
cy.focused().realPress("Tab");
cy.focused().realPress("Tab");
cy.focused().realPress("Space");
Expand Down
64 changes: 31 additions & 33 deletions packages/main/src/Calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,11 @@ import CalendarHeaderCss from "./generated/themes/CalendarHeader.css.js";
import { CALENDAR_HEADER_NEXT_BUTTON, CALENDAR_HEADER_PREVIOUS_BUTTON } from "./generated/i18n/i18n-defaults.js";
import type { YearRangePickerChangeEventDetail } from "./YearRangePicker.js";

interface ICalendarPicker {
_showPreviousPage: () => void,
_showNextPage: () => void,
interface ICalendarPicker extends HTMLElement {
_showPreviousPage: () => void | Promise<void>,
_showNextPage: () => void | Promise<void>,
_hasPreviousPage: () => boolean,
_hasNextPage: () => boolean,
_autoFocus?: boolean,
_currentYearRange?: CalendarYearRangeT,
}

Expand Down Expand Up @@ -335,6 +334,11 @@ class Calendar extends CalendarPart {
this._valueIsProcessed = false;
}

async _focusCurrentPicker() {
await renderFinished();
this._currentPickerDOM.focus();
}

/**
* @private
*/
Expand Down Expand Up @@ -465,7 +469,6 @@ class Calendar extends CalendarPart {
if (defaultTypes.includes(this._selectedItemType)) {
this._selectedItemType = "None"; // In order to avoid filtering of default types
}
this._currentPickerDOM._autoFocus = false;
}

/**
Expand Down Expand Up @@ -524,40 +527,40 @@ class Calendar extends CalendarPart {
/**
* The user clicked the "month" button in the header
*/
onHeaderShowMonthPress() {
this.showMonth();
async onHeaderShowMonthPress() {
await this.showMonth();
this.fireDecoratorEvent("show-month-view");
}

showMonth() {
this._currentPickerDOM._autoFocus = false;
async showMonth() {
this._currentPicker = "month";
await this._focusCurrentPicker();
}

/**
* The user clicked the "year" button in the header
*/
onHeaderShowYearPress() {
this.showYear();
async onHeaderShowYearPress() {
await this.showYear();
this.fireDecoratorEvent("show-year-view");
}

showYear() {
this._currentPickerDOM._autoFocus = false;
async showYear() {
this._currentPicker = "year";
await this._focusCurrentPicker();
}

/**
* The user clicked the "year range" button in the YearPicker header
*/
onHeaderShowYearRangePress() {
this.showYearRange();
async onHeaderShowYearRangePress() {
await this.showYearRange();
this.fireDecoratorEvent("show-year-range-view");
}

showYearRange() {
this._currentPickerDOM._autoFocus = false;
async showYearRange() {
this._currentPicker = "yearrange";
await this._focusCurrentPicker();
}

get _currentPickerDOM() {
Expand All @@ -570,21 +573,13 @@ class Calendar extends CalendarPart {
*/
onHeaderPreviousPress() {
this._currentPickerDOM._showPreviousPage();

if (this.calendarLegend) {
this._currentPickerDOM._autoFocus = true;
}
}

/**
* The year clicked the "Next" button in the header
*/
onHeaderNextPress() {
this._currentPickerDOM._showNextPage();

if (this.calendarLegend) {
this._currentPickerDOM._autoFocus = true;
}
}

_setSecondaryCalendarTypeButtonText() {
Expand Down Expand Up @@ -710,46 +705,47 @@ class Calendar extends CalendarPart {
this._fireEventAndUpdateSelectedDates(e.detail.dates);
}

onSelectedMonthChange(e: CustomEvent<MonthPickerChangeEventDetail>) {
async onSelectedMonthChange(e: CustomEvent<MonthPickerChangeEventDetail>) {
this.timestamp = e.detail.timestamp;

if (this._pickersMode === CalendarPickersMode.DAY_MONTH_YEAR) {
this._currentPicker = "day";
await this._focusCurrentPicker();
} else {
this._fireEventAndUpdateSelectedDates(e.detail.dates);
}

this._currentPickerDOM._autoFocus = true;
}

onSelectedYearChange(e: CustomEvent<YearPickerChangeEventDetail>) {
async onSelectedYearChange(e: CustomEvent<YearPickerChangeEventDetail>) {
this.timestamp = e.detail.timestamp;

if (this._pickersMode === CalendarPickersMode.DAY_MONTH_YEAR) {
this._currentPicker = "day";
await this._focusCurrentPicker();
} else if (this._pickersMode === CalendarPickersMode.MONTH_YEAR) {
this._currentPicker = "month";
await this._focusCurrentPicker();
} else {
this._fireEventAndUpdateSelectedDates(e.detail.dates);
}

this._currentPickerDOM._autoFocus = true;
}

onSelectedYearRangeChange(e: CustomEvent<YearRangePickerChangeEventDetail>) {
async onSelectedYearRangeChange(e: CustomEvent<YearRangePickerChangeEventDetail>) {
this.timestamp = e.detail.timestamp;
this._currentPicker = "year";
this._currentPickerDOM._autoFocus = true;
await this._focusCurrentPicker();
}

onNavigate(e: CustomEvent) {
this.timestamp = e.detail.timestamp;
this._focusCurrentPicker();
}

_onkeydown(e: KeyboardEvent) {
if (isF4(e) && this._currentPicker !== "month") {
this._currentPicker = "month";
this.fireDecoratorEvent("show-month-view");
this._focusCurrentPicker();
}

if (!isF4Shift(e)) {
Expand All @@ -759,9 +755,11 @@ class Calendar extends CalendarPart {
if (this._currentPicker !== "year") {
this._currentPicker = "year";
this.fireDecoratorEvent("show-year-view");
this._focusCurrentPicker();
} else {
this._currentPicker = "yearrange";
this.fireDecoratorEvent("show-year-range-view");
this._focusCurrentPicker();
}
}

Expand Down
45 changes: 28 additions & 17 deletions packages/main/src/DayPicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type LocaleData from "@ui5/webcomponents-localization/dist/LocaleData.js"
import getCachedLocaleDataInstance from "@ui5/webcomponents-localization/dist/getCachedLocaleDataInstance.js";
import InvisibleMessageMode from "@ui5/webcomponents-base/dist/types/InvisibleMessageMode.js";
import announce from "@ui5/webcomponents-base/dist/util/InvisibleMessage.js";
import { renderFinished } from "@ui5/webcomponents-base/dist/Render.js";
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
import {
isSpace,
Expand Down Expand Up @@ -195,8 +196,6 @@ class DayPicker extends CalendarPart implements ICalendarPicker {
@query("[data-sap-focus-ref]")
_focusableDay!: HTMLElement;

_autoFocus?: boolean;

@i18n("@ui5/webcomponents")
static i18nBundle: I18nBundle;

Expand Down Expand Up @@ -404,12 +403,6 @@ class DayPicker extends CalendarPart implements ICalendarPicker {
return dayNames.some(dayName => dayName.length > 4);
}

onAfterRendering() {
if (this._autoFocus && !this._hidden) {
this.focus();
}
}

_focusCorrectDay() {
if (this._shouldFocusDay) {
this._focusableDay.focus();
Expand All @@ -420,15 +413,11 @@ class DayPicker extends CalendarPart implements ICalendarPicker {
return document.activeElement !== this._focusableDay && this._specialCalendarDates.length === 0;
}

_onfocusin() {
this._autoFocus = true;
async _onfocusin() {
await renderFinished();
this._focusCorrectDay();
}

_onfocusout() {
this._autoFocus = false;
}

/**
* Tells if the day is selected (dark blue).
* @param timestamp
Expand Down Expand Up @@ -618,6 +607,21 @@ class DayPicker extends CalendarPart implements ICalendarPicker {
}
}

/**
* Sets the focus reference to the day that was clicked with mousedown.
* @param e
* @private
*/
_onmousedown(e: MouseEvent) {
const target = e.target as HTMLElement;
const clickedItem = target.closest(".ui5-dp-item") as HTMLElement;

if (clickedItem && this._isDayPressed(clickedItem)) {
const timestamp = this._getTimestampFromDom(clickedItem);
this._setTimestamp(timestamp);
}
}

_onkeydown(e: KeyboardEvent) {
let preventDefault = true;

Expand Down Expand Up @@ -723,16 +727,20 @@ class DayPicker extends CalendarPart implements ICalendarPicker {
* Called by the Calendar component.
* @protected
*/
_showPreviousPage() {
async _showPreviousPage() {
this._modifyTimestampBy(-1, "month", false);
await renderFinished();
this._focusCorrectDay();
}

/**
* Called by the Calendar component.
* @protected
*/
_showNextPage() {
async _showNextPage() {
this._modifyTimestampBy(1, "month", false);
await renderFinished();
this._focusCorrectDay();
}

/**
Expand All @@ -742,13 +750,16 @@ class DayPicker extends CalendarPart implements ICalendarPicker {
* @param preserveDate whether to preserve the day of the month (f.e. 15th of March + 1 month = 15th of April)
* @private
*/
_modifyTimestampBy(amount: number, unit: string, preserveDate?: boolean) {
async _modifyTimestampBy(amount: number, unit: string, preserveDate?: boolean) {
// Modify the current timestamp
this._safelyModifyTimestampBy(amount, unit, preserveDate);
this._updateSecondTimestamp();

// Notify the calendar to update its timestamp
this.fireDecoratorEvent("navigate", { timestamp: this.timestamp! });

await renderFinished();
this._focusCorrectDay();
}

/**
Expand Down
3 changes: 1 addition & 2 deletions packages/main/src/DayPickerTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ export default function DayPickerTemplate(this: DayPicker) {
onKeyDown={this._onkeydown}
onKeyUp={this._onkeyup}
onClick={this._onclick}
onMouseDown={this._onmousedown}
onMouseOver={this._onmouseover}
onFocusIn={this._onfocusin}
onFocusOut={this._onfocusout}
>
<div id={`${this._id}-content`} class="ui5-dp-content" role="grid" aria-roledescription={this.ariaRoledescription}>
<div role="row" class="ui5-dp-days-names-container">
Expand Down
Loading
Loading