diff --git a/packages/main/cypress/specs/DateTimePicker.cy.tsx b/packages/main/cypress/specs/DateTimePicker.cy.tsx
index 837371e45285..db29848bcdee 100644
--- a/packages/main/cypress/specs/DateTimePicker.cy.tsx
+++ b/packages/main/cypress/specs/DateTimePicker.cy.tsx
@@ -343,15 +343,7 @@ describe("DateTimePicker general interaction", () => {
.ui5DateTimePickerClose();
});
- // Skipped: this test has been failing intermittently on CI for weeks.
- // The "Unstable test, needs investigation" note below has been there from before.
- // Root cause appears to be a focus race in TimeSelectionClocks._activateClock,
- // which waits for `animationend` to advance focus between hours/minutes/seconds.
- // When animations are disabled (as this test does via setAnimationMode(None)),
- // `animationend` never fires, so the next clock button never becomes focused.
- // Skipping until the underlying component is fixed.
- //Unstable test, needs investigation
- it.skip("tests selection of 12:34:56 AM", () => {
+ it("tests selection of 12:34:56 AM", () => {
setAnimationMode(AnimationMode.None);
cy.mount();
diff --git a/packages/main/src/Calendar.ts b/packages/main/src/Calendar.ts
index e012dc354379..5c8043978d8f 100644
--- a/packages/main/src/Calendar.ts
+++ b/packages/main/src/Calendar.ts
@@ -27,7 +27,7 @@ import CalendarDate from "./CalendarDate.js";
import CalendarDateRange from "./CalendarDateRange.js";
import "./SpecialCalendarDate.js";
import CalendarPart from "./CalendarPart.js";
-import type { DayPickerChangeEventDetail } from "./DayPicker.js";
+import type { DayPickerChangeEventDetail, DayPickerNavigateEventDetail } from "./DayPicker.js";
import type { MonthPickerChangeEventDetail } from "./MonthPicker.js";
import type { YearPickerChangeEventDetail } from "./YearPicker.js";
import CalendarSelectionMode from "./types/CalendarSelectionMode.js";
@@ -918,8 +918,14 @@ class Calendar extends CalendarPart {
this.switchToYearPicker();
}
- async onNavigate(e: CustomEvent) {
+ async onNavigate(e: CustomEvent) {
this.timestamp = e.detail.timestamp;
+ // Mouse-driven navigation handles its own focus; the click already landed
+ // where the user wants. Refocusing after the deferred render would steal
+ // focus from a sibling component (e.g. a time picker in DateTimePicker).
+ if (e.detail.mouse) {
+ return;
+ }
await renderFinished();
this._currentPickerDOM.focus();
}
diff --git a/packages/main/src/DayPicker.ts b/packages/main/src/DayPicker.ts
index f47dc63d4c6f..25a793bd42a1 100644
--- a/packages/main/src/DayPicker.ts
+++ b/packages/main/src/DayPicker.ts
@@ -104,6 +104,7 @@ type DayPickerChangeEventDetail = {
type DayPickerNavigateEventDetail = {
timestamp: number,
+ mouse?: boolean,
}
/**
@@ -612,7 +613,7 @@ class DayPicker extends CalendarPart implements ICalendarPicker {
}
this._safelySetTimestamp(this._getTimestampFromDom(target));
- this.fireDecoratorEvent("navigate", { timestamp: this.timestamp! });
+ this.fireDecoratorEvent("navigate", { timestamp: this.timestamp!, mouse: true });
}
/**
diff --git a/packages/main/src/TimeSelectionClocks.ts b/packages/main/src/TimeSelectionClocks.ts
index 9ab39f1922a9..7cf14c9b979c 100644
--- a/packages/main/src/TimeSelectionClocks.ts
+++ b/packages/main/src/TimeSelectionClocks.ts
@@ -1,6 +1,8 @@
import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
import property from "@ui5/webcomponents-base/dist/decorators/property.js";
import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
+import AnimationMode from "@ui5/webcomponents-base/dist/types/AnimationMode.js";
+import { getAnimationMode } from "@ui5/webcomponents-base/dist/config/AnimationMode.js";
import "@ui5/webcomponents-localization/dist/features/calendar/Gregorian.js"; // default calendar for bundling
import {
isDown,
@@ -416,6 +418,10 @@ class TimeSelectionClocks extends TimePickerInternals {
return;
}
+ if (getAnimationMode() === AnimationMode.None) {
+ skipAnimation = true;
+ }
+
const currentClockComponent = this._clockComponent(this._activeIndex);
const newClockComponent = this._clockComponent(clockIndex);
@@ -428,7 +434,7 @@ class TimeSelectionClocks extends TimePickerInternals {
newClockComponent._skipAnimation = true;
this._activateClock(clockIndex);
} else {
- currentClockComponent?._firstNumberElement?.addEventListener("animationend", () => this._activateClock(clockIndex), { once: true });
+ currentClockComponent?._firstNumberElement?.addEventListener("animationend", () => { this._activateClock(clockIndex); }, { once: true });
currentClockComponent?._clockWrapper?.classList.add("ui5-tp-clock-transition");
}
}
@@ -438,12 +444,12 @@ class TimeSelectionClocks extends TimePickerInternals {
* @param clockIndex the index of the clock to be activated
*/
_activateClock(clockIndex: number) {
- const newButton = this._buttonComponent(clockIndex);
-
this._entities[this._activeIndex].active = false;
this._activeIndex = clockIndex;
this._entities[this._activeIndex].active = true;
- newButton && newButton.focus();
+
+ const newButton = this._buttonComponent(clockIndex);
+ newButton?.getFocusDomRef()?.focus();
}
/**