Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/young-pears-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-components': patch
---

Updated `post-popovercontainer` to fix a tooltip desynchronization issue when hovering quickly in and out.
10 changes: 6 additions & 4 deletions packages/components/src/components/post-menu/post-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,12 @@ export class PostMenu {

if (this.isVisible) {
this.lastFocusedElement = this.root?.activeElement as HTMLElement;
const menuItems = this.getSlottedItems();
if (menuItems.length > 0) {
(menuItems[0] as HTMLElement).focus();
}
requestAnimationFrame(() => {
const menuItems = this.getSlottedItems();
if (menuItems.length > 0) {
(menuItems[0] as HTMLElement).focus();
}
});
} else if (this.lastFocusedElement) {
this.lastFocusedElement.focus();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ export class PostPopovercontainer {
this.host.style.setProperty('--post-safe-space-cursor-y', `${event.clientY}px`);
}

private currentAnimation: Animation | null = null;

connectedCallback() {
if (IS_BROWSER && !isSupported()) {
apply();
Expand All @@ -183,7 +185,6 @@ export class PostPopovercontainer {
async show(target: HTMLElement) {
if (this.toggleTimeoutId) return;
this.eventTarget = target;
if (this.toggleTimeoutId) return;
this.calculatePosition();
this.host.showPopover();
}
Expand All @@ -193,23 +194,21 @@ export class PostPopovercontainer {
*/
@Method()
async open() {
const content = this.host.querySelector('.popover-content');
const content: HTMLElement = this.host.querySelector('.popover-content');
this.startAutoupdates();

if (content) {
const animation = popIn(content);

if (animation?.playState === 'running') {
// Only run animation and emit related events if animation is defined
if (this.animation === null) {
// No animation case
this.postBeforeToggle.emit({ willOpen: true });
this.postBeforeShow.emit({ first: this.hasOpenedOnce });
}

animation?.finished.then(() => {
this.postToggle.emit({ isOpen: true });
this.postShow.emit({ first: this.hasOpenedOnce });

if (this.hasOpenedOnce) this.hasOpenedOnce = false;
});
} else {
this.runOpenAnimation(content);
}
}

if (this.safeSpace) {
Expand All @@ -230,19 +229,59 @@ export class PostPopovercontainer {
window.removeEventListener('mousemove', this.mouseTrackingHandler.bind(this));
}

// Cancel any running animation
if (this.animation !== null && this.currentAnimation) {
this.currentAnimation.cancel();
this.currentAnimation = null;
}

this.postBeforeToggle.emit({ willOpen: false });
this.postToggle.emit({ isOpen: false });
this.postHide.emit();
}

/**
* Runs the animation and emits the toggle/show/hide events in the correct timing
*/

private async runOpenAnimation(element: HTMLElement) {
let animation: Animation | undefined;

try {
animation = popIn(element);

this.currentAnimation = animation;

if (animation.playState === 'running') {
this.postBeforeToggle.emit({ willOpen: true });
this.postBeforeShow.emit({ first: this.hasOpenedOnce });
}

await animation.finished;

this.postToggle.emit({ isOpen: true });
this.postShow.emit({ first: this.hasOpenedOnce });

this.hasOpenedOnce = true;
} catch (err) {
console.warn('Animation failed or was interrupted:', err);
// Reset all states to closing
this.postBeforeToggle.emit({ willOpen: false });
this.postBeforeShow.emit({ first: this.hasOpenedOnce });
this.postToggle.emit({ isOpen: false });
} finally {
if (this.currentAnimation === animation) {
this.currentAnimation = null;
}
}
}

/**
* Programmatically hide the popovercontainer
*/
@Method()
async hide() {
if (!this.toggleTimeoutId) {
if (this.eventTarget && this.eventTarget instanceof HTMLElement) {
this.eventTarget.focus();
}
this.eventTarget = null;
this.host.hidePopover();
this.postHide.emit();
Expand Down
Loading