diff --git a/src/elements/clock/__snapshots__/clock.snapshot.spec.snap.js b/src/elements/clock/__snapshots__/clock.snapshot.spec.snap.js
index 259b9de222..501cc93cf9 100644
--- a/src/elements/clock/__snapshots__/clock.snapshot.spec.snap.js
+++ b/src/elements/clock/__snapshots__/clock.snapshot.spec.snap.js
@@ -35,7 +35,7 @@ snapshots["sbb-clock renders with fixed time DOM"] =
`
`;
diff --git a/src/elements/clock/clock.ts b/src/elements/clock/clock.ts
index 957102055d..9a76d1fa7d 100644
--- a/src/elements/clock/clock.ts
+++ b/src/elements/clock/clock.ts
@@ -86,20 +86,28 @@ export class SbbClockElement extends LitElement {
/** Move the minutes hand every minute. */
private _handMovement?: ReturnType;
- protected override willUpdate(changedProperties: PropertyValues): void {
+ protected override async willUpdate(changedProperties: PropertyValues): Promise {
super.willUpdate(changedProperties);
if (!isServer && changedProperties.has('now')) {
- if (this.now) {
- this._removeSecondsAnimationStyles();
- this._removeHoursAnimationStyles();
- this._stopClock();
- } else {
- this._startClock();
- }
+ await this._startOrConfigureClock();
}
}
+ protected override async firstUpdated(changedProperties: PropertyValues): Promise {
+ super.firstUpdated(changedProperties);
+
+ if (!isServer) {
+ document.addEventListener('visibilitychange', this._handlePageVisibilityChange, false);
+ await this._startOrConfigureClock();
+ }
+ }
+
+ public override disconnectedCallback(): void {
+ super.disconnectedCallback();
+ this._removeEventListeners();
+ }
+
private _handlePageVisibilityChange = async (): Promise => {
if (document.visibilityState === 'hidden') {
await this._stopClock();
@@ -108,40 +116,51 @@ export class SbbClockElement extends LitElement {
}
};
- private _addEventListeners(): void {
- document.addEventListener('visibilitychange', this._handlePageVisibilityChange, false);
+ private async _startOrConfigureClock(): Promise {
+ if (this.now) {
+ await this._stopClock();
+ this._resetSecondsHandAnimation();
+ this._setHandsStartingPosition();
+ } else {
+ await this._startClock();
+ }
}
- private _removeEventListeners(): void {
- document?.removeEventListener('visibilitychange', this._handlePageVisibilityChange);
- this._clockHandHours?.removeEventListener('animationend', this._moveHoursHandFn);
- this._clockHandSeconds?.removeEventListener('animationend', this._moveMinutesHandFn);
- clearInterval(this._handMovement);
- }
+ /** Starts the clock by defining the hands starting position then starting the animations. */
+ private async _startClock(): Promise {
+ this._clockHandHours?.addEventListener(
+ 'animationend',
+ this._moveHoursHandFn,
+ ADD_EVENT_LISTENER_OPTIONS,
+ );
+ this._clockHandSeconds?.addEventListener(
+ 'animationend',
+ this._moveMinutesHandFn,
+ ADD_EVENT_LISTENER_OPTIONS,
+ );
- private _removeHoursAnimationStyles(): void {
- this._clockHandHours?.classList.remove('sbb-clock__hand-hours--initial-hour');
- this.style.removeProperty('--sbb-clock-hours-animation-start-angle');
- this.style.removeProperty('--sbb-clock-hours-animation-duration');
- }
+ await new Promise(() =>
+ setTimeout(() => {
+ this._setHandsStartingPosition();
- private _removeSecondsAnimationStyles(): void {
- this._clockHandSeconds?.classList.remove('sbb-clock__hand-seconds--initial-minute');
- this._clockHandMinutes?.classList.remove('sbb-clock__hand-minutes--no-transition');
- this.style.removeProperty('--sbb-clock-seconds-animation-start-angle');
- this.style.removeProperty('--sbb-clock-seconds-animation-duration');
+ this.style?.setProperty('--sbb-clock-animation-play-state', 'running');
+ }, INITIAL_TIMEOUT_DURATION),
+ );
}
- /** Given the current date, calculates the hh/mm/ss values and the hh/mm/ss left to the next midnight. */
- private _assignCurrentTime(): void {
- const date = this.now ? null : new Date();
- const [hours, minutes, seconds] = date
- ? [date.getHours(), date.getMinutes(), date.getSeconds()]
- : this.now!.split(':').map((p) => +p);
+ /** Stops the clock by removing all the animations. */
+ private async _stopClock(): Promise {
+ clearInterval(this._handMovement);
- this._hours = hours % 12;
- this._minutes = minutes;
- this._seconds = seconds;
+ this._removeSecondsAnimationStyles();
+ this._removeHoursAnimationStyles();
+
+ this._clockHandHours?.removeEventListener('animationend', this._moveHoursHandFn);
+ this._clockHandSeconds?.removeEventListener('animationend', this._moveMinutesHandFn);
+
+ this._clockHandMinutes?.classList.add('sbb-clock__hand-minutes--no-transition');
+
+ this.style?.setProperty('--sbb-clock-animation-play-state', 'paused');
}
/** Set the starting position for the three hands on the clock face. */
@@ -185,11 +204,22 @@ export class SbbClockElement extends LitElement {
this._clockHandSeconds?.classList.add('sbb-clock__hand-seconds--initial-minute');
this._clockHandHours?.classList.add('sbb-clock__hand-hours--initial-hour');
- this.style?.setProperty('--sbb-clock-animation-play-state', 'running');
this.toggleAttribute('data-initialized', true);
}
+ /** Given the current date, calculates the hh/mm/ss values and the hh/mm/ss left to the next midnight. */
+ private _assignCurrentTime(): void {
+ const date = this.now ? null : new Date();
+ const [hours, minutes, seconds] = date
+ ? [date.getHours(), date.getMinutes(), date.getSeconds()]
+ : this.now!.split(':').map((p) => +p);
+
+ this._hours = hours % 12;
+ this._minutes = minutes;
+ this._seconds = seconds;
+ }
+
/** Set the starting position for the minutes hand. */
private _setMinutesHand(): void {
this._clockHandMinutes?.style.setProperty(
@@ -230,67 +260,39 @@ export class SbbClockElement extends LitElement {
this._setMinutesHand();
}
- /** Stops the clock by removing all the animations. */
- private async _stopClock(): Promise {
- clearInterval(this._handMovement);
-
- if (this.now) {
- this._setHandsStartingPosition();
-
- // Wait a tick to before animation is added. Otherwise, the animation gets not completely
- // removed which can lead to a mispositioned seconds hand.
- await new Promise((resolve) => setTimeout(resolve));
-
- this._clockHandSeconds?.classList.add('sbb-clock__hand-seconds--initial-minute');
- this._clockHandHours?.classList.add('sbb-clock__hand-hours--initial-hour');
- } else {
- this._removeSecondsAnimationStyles();
- this._removeHoursAnimationStyles();
+ /**
+ * Removing animation by overriding with empty string,
+ * then triggering a reflow and re add original animation by removing override.
+ * @private
+ */
+ private _resetSecondsHandAnimation(): void {
+ if (!this._clockHandSeconds) {
+ return;
}
+ this._clockHandSeconds.style.animation = '';
+ // Hack to trigger reflow
+ this._clockHandSeconds.offsetHeight;
+ this._clockHandSeconds.style.removeProperty('animation');
+ }
+ private _removeEventListeners(): void {
+ document?.removeEventListener('visibilitychange', this._handlePageVisibilityChange);
this._clockHandHours?.removeEventListener('animationend', this._moveHoursHandFn);
this._clockHandSeconds?.removeEventListener('animationend', this._moveMinutesHandFn);
-
- this._clockHandMinutes?.classList.add('sbb-clock__hand-minutes--no-transition');
-
- this.style?.setProperty('--sbb-clock-animation-play-state', 'paused');
- }
-
- /** Starts the clock by defining the hands starting position then starting the animations. */
- private async _startClock(): Promise {
- this._clockHandHours?.addEventListener(
- 'animationend',
- this._moveHoursHandFn,
- ADD_EVENT_LISTENER_OPTIONS,
- );
- this._clockHandSeconds?.addEventListener(
- 'animationend',
- this._moveMinutesHandFn,
- ADD_EVENT_LISTENER_OPTIONS,
- );
-
- await new Promise(() =>
- setTimeout(() => this._setHandsStartingPosition(), INITIAL_TIMEOUT_DURATION),
- );
+ clearInterval(this._handMovement);
}
- protected override async firstUpdated(changedProperties: PropertyValues): Promise {
- super.firstUpdated(changedProperties);
-
- if (!isServer) {
- this._addEventListeners();
-
- if (this.now) {
- await this._stopClock();
- } else {
- await this._startClock();
- }
- }
+ private _removeHoursAnimationStyles(): void {
+ this._clockHandHours?.classList.remove('sbb-clock__hand-hours--initial-hour');
+ this.style.removeProperty('--sbb-clock-hours-animation-start-angle');
+ this.style.removeProperty('--sbb-clock-hours-animation-duration');
}
- public override disconnectedCallback(): void {
- super.disconnectedCallback();
- this._removeEventListeners();
+ private _removeSecondsAnimationStyles(): void {
+ this._clockHandSeconds?.classList.remove('sbb-clock__hand-seconds--initial-minute');
+ this._clockHandMinutes?.classList.remove('sbb-clock__hand-minutes--no-transition');
+ this.style.removeProperty('--sbb-clock-seconds-animation-start-angle');
+ this.style.removeProperty('--sbb-clock-seconds-animation-duration');
}
protected override render(): TemplateResult {