Skip to content

Commit 473e73c

Browse files
authored
Revert "When PopOverButton popover opens, close tooltip on the same element" (#7941)
2 parents de3d02d + 2bc3601 commit 473e73c

File tree

4 files changed

+37
-64
lines changed

4 files changed

+37
-64
lines changed

packages/components/src/components/button/component.tsx

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,22 +67,19 @@ import clsx from 'clsx';
6767
export class KolButtonWc implements InternalButtonAPI, FocusableElement {
6868
@Element() private readonly host?: HTMLKolButtonWcElement;
6969
private buttonRef?: HTMLButtonElement;
70-
private tooltipRef?: HTMLKolTooltipWcElement;
7170

7271
private readonly internalDescriptionById = nonce();
7372

73+
private readonly catchRef = (ref?: HTMLButtonElement) => {
74+
this.buttonRef = ref;
75+
};
76+
7477
@Method()
7578
// eslint-disable-next-line @typescript-eslint/require-await
7679
public async kolFocus() {
7780
this.buttonRef?.focus();
7881
}
7982

80-
@Method()
81-
// eslint-disable-next-line @typescript-eslint/require-await
82-
public async hideTooltip() {
83-
void this.tooltipRef?.hideTooltip();
84-
}
85-
8683
private readonly onClick = (event: MouseEvent) => {
8784
if (this.state._type === 'submit') {
8885
propagateSubmitEventToForm({
@@ -125,7 +122,7 @@ export class KolButtonWc implements InternalButtonAPI, FocusableElement {
125122
return (
126123
<Host>
127124
<button
128-
ref={(ref) => (this.buttonRef = ref)}
125+
ref={this.catchRef}
129126
accessKey={this.state._accessKey || undefined}
130127
aria-controls={this.state._ariaControls}
131128
aria-describedby={hasAriaDescription ? this.internalDescriptionById : undefined}
@@ -161,7 +158,6 @@ export class KolButtonWc implements InternalButtonAPI, FocusableElement {
161158
</KolSpanFc>
162159
</button>
163160
<KolTooltipWcTag
164-
ref={(ref) => (this.tooltipRef = ref)}
165161
/**
166162
* Dieses Aria-Hidden verhindert das doppelte Vorlesen des Labels,
167163
* verhindert aber nicht das Aria-Labelledby vorgelesen wird.

packages/components/src/components/popover-button/component.tsx

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,11 @@ export class KolPopoverButton implements PopoverButtonProps {
6060
// Reset the flag after the event loop tick.
6161
this.justClosed = false;
6262
}, 10); // timeout of 0 should be sufficient but doesn't work in Safari Mobile (needs further investigation).
63-
} else {
64-
if (this.refPopover) {
65-
/**
66-
* Avoid "flicker" by hiding the element until the position is set in the `toggle` event handler. `alignFloatingElements` is responsible for setting the visibility back to 'visible'.
67-
*/
68-
this.refPopover.style.visibility = 'hidden';
69-
}
70-
71-
void this.refButton?.hideTooltip();
63+
} else if (this.refPopover) {
64+
/**
65+
* Avoid "flicker" by hiding the element until the position is set in the `toggle` event handler. `alignFloatingElements` is responsible for setting the visibility back to 'visible'.
66+
*/
67+
this.refPopover.style.visibility = 'hidden';
7268
}
7369
}
7470

packages/components/src/components/popover-button/popover-button.e2e.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,4 @@ test.describe('kol-popover-button', () => {
3737
await button.click({ force: true });
3838
await expect(popover).not.toBeVisible();
3939
});
40-
41-
test('should hide its tooltip when popover is shown', async ({ page }) => {
42-
await page.setContent(`
43-
<kol-popover-button _label="Toggle popover" _icons="codicon codicon-info" _hide-label>
44-
Popover content
45-
</kol-popover-button>
46-
`);
47-
const button = page.getByTestId('popover-button').locator('button');
48-
const tooltip = page.locator('kol-tooltip-wc');
49-
50-
await button.hover();
51-
await expect(tooltip).toBeVisible();
52-
53-
await button.click();
54-
await expect(tooltip).not.toBeVisible();
55-
});
5640
});

packages/components/src/components/tooltip/component.tsx

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,12 @@ import { autoUpdate } from '@floating-ui/dom';
22
import type { AlignPropType, BadgeTextPropType, IdPropType, LabelPropType, TooltipAPI, TooltipStates } from '../../schema';
33
import { getDocument, validateBadgeText, validateAlign, validateId, validateLabel } from '../../schema';
44
import type { JSX } from '@stencil/core';
5-
import { Method } from '@stencil/core';
65
import { Component, Element, h, Host, Prop, State, Watch } from '@stencil/core';
76

87
import { alignFloatingElements } from '../../utils/align-floating-elements';
98
import { hideOverlay, showOverlay } from '../../utils/overlay';
109
import { KolSpanFc } from '../../functional-components';
1110

12-
// Timing Guidelines for Exposing Hidden Content: https://www.nngroup.com/articles/timing-exposing-content/
13-
const TOOLTIP_DELAY = 300;
14-
1511
/**
1612
* @internal
1713
*/
@@ -25,6 +21,8 @@ export class KolTooltipWc implements TooltipAPI {
2521
private arrowElement?: HTMLDivElement;
2622
private previousSibling?: Element | null;
2723
private tooltipElement?: HTMLDivElement;
24+
private hasFocusIn = false;
25+
private hasMouseIn = false;
2826

2927
private cleanupAutoPositioning?: () => void;
3028

@@ -53,26 +51,7 @@ export class KolTooltipWc implements TooltipAPI {
5351
}
5452
};
5553

56-
private showTooltipTimeout?: ReturnType<typeof setTimeout>;
57-
private showTooltipWithDelay = (): void => {
58-
clearTimeout(this.showTooltipTimeout);
59-
this.showTooltipTimeout = setTimeout(() => {
60-
this.showTooltip();
61-
}, TOOLTIP_DELAY);
62-
};
63-
64-
private hideTooltipTimeout?: ReturnType<typeof setTimeout>;
65-
private hideTooltipWithDelay = (): void => {
66-
clearTimeout(this.hideTooltipTimeout);
67-
this.hideTooltipTimeout = setTimeout(() => {
68-
void this.hideTooltip();
69-
}, TOOLTIP_DELAY);
70-
};
71-
72-
@Method()
73-
// eslint-disable-next-line @typescript-eslint/require-await
74-
public async hideTooltip() {
75-
clearTimeout(this.showTooltipTimeout); // Cancel scheduled tooltips
54+
private hideTooltip = (): void => {
7655
if (this.tooltipElement /* SSR instanceof HTMLElement */) {
7756
hideOverlay(this.tooltipElement);
7857
this.tooltipElement.style.setProperty('display', 'none');
@@ -83,25 +62,29 @@ export class KolTooltipWc implements TooltipAPI {
8362
}
8463
}
8564
getDocument().removeEventListener('keyup', this.hideTooltipByEscape);
86-
}
65+
};
8766

8867
private hideTooltipByEscape = (event: KeyboardEvent): void => {
8968
if (event.key === 'Escape') {
90-
void this.hideTooltip();
69+
this.hideTooltip();
9170
}
9271
};
9372

9473
private handleMouseEnter() {
95-
this.showTooltipWithDelay();
74+
this.hasMouseIn = true;
75+
this.showOrHideTooltip();
9676
}
9777
private handleMouseleave() {
98-
this.hideTooltipWithDelay();
78+
this.hasMouseIn = false;
79+
this.showOrHideTooltip();
9980
}
10081
private handleFocusIn() {
101-
this.showTooltipWithDelay();
82+
this.hasFocusIn = true;
83+
this.showOrHideTooltip();
10284
}
10385
private handleFocusout() {
104-
this.hideTooltipWithDelay();
86+
this.hasFocusIn = false;
87+
this.showOrHideTooltip();
10588
}
10689

10790
private addListeners = (el: Element): void => {
@@ -200,6 +183,20 @@ export class KolTooltipWc implements TooltipAPI {
200183
});
201184
}
202185

186+
private overFocusTimeout?: ReturnType<typeof setTimeout>;
187+
188+
private showOrHideTooltip = (): void => {
189+
clearTimeout(this.overFocusTimeout);
190+
this.overFocusTimeout = setTimeout(() => {
191+
if (this.hasMouseIn || this.hasFocusIn) {
192+
this.showTooltip();
193+
} else {
194+
this.hideTooltip();
195+
}
196+
// Timing Guidelines for Exposing Hidden Content: https://www.nngroup.com/articles/timing-exposing-content/
197+
}, 300);
198+
};
199+
203200
public componentWillLoad(): void {
204201
this.validateBadgeText(this._badgeText);
205202
this.validateAlign(this._align);

0 commit comments

Comments
 (0)