Skip to content

Commit a95ca8d

Browse files
committed
fix(tooltip): rename internal flags for clarity and enhance accessibility attributes, also add a timeout before calling hideWithEvent
1 parent 3baadca commit a95ca8d

File tree

1 file changed

+32
-23
lines changed

1 file changed

+32
-23
lines changed

src/components/tooltip/tooltip.ts

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import {
1919
} from './tooltip-event-controller.js';
2020
import service from './tooltip-service.js';
2121

22-
// TODO: Expose events
2322
export interface IgcTooltipComponentEventMap {
2423
igcOpening: CustomEvent<Element | null>;
2524
igcOpened: CustomEvent<Element | null>;
@@ -60,8 +59,8 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
6059
private _animationPlayer = addAnimationController(this, this._containerRef);
6160

6261
private _timeoutId?: number;
63-
private toBeShown = false;
64-
private toBeHidden = false;
62+
private _toBeShown = false;
63+
private _toBeHidden = false;
6564
private _open = false;
6665
private _showTriggers = ['pointerenter'];
6766
private _hideTriggers = ['pointerleave'];
@@ -205,6 +204,8 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
205204

206205
this._internals = this.attachInternals();
207206
this._internals.role = 'tooltip';
207+
this._internals.ariaAtomic = 'true';
208+
this._internals.ariaLive = 'polite';
208209
}
209210

210211
protected override async firstUpdated() {
@@ -255,10 +256,23 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
255256
return this._animationPlayer.playExclusive(animation);
256257
}
257258

259+
/**
260+
* Immediately stops any ongoing animation and resets the tooltip state.
261+
*
262+
* This method is used in edge cases when a transition needs to be forcefully interrupted,
263+
* such as when a tooltip is in the middle of showing or hiding and the user suddenly
264+
* triggers the opposite action (e.g., hovers in and out rapidly).
265+
*
266+
* It:
267+
* - Reverts `open` based on whether it was mid-hide or mid-show.
268+
* - Clears internal transition flags (`_toBeShown`, `_toBeHidden`).
269+
* - Stops any active animations, causing `_toggleAnimation()` to return false.
270+
*
271+
*/
258272
private async _forceAnimationStop() {
259-
this.toBeShown = false;
260-
this.toBeHidden = false;
261-
this.open = !this.open;
273+
this.open = this._toBeHidden;
274+
this._toBeShown = false;
275+
this._toBeHidden = false;
262276
this._animationPlayer.stopAll();
263277
}
264278

@@ -276,9 +290,9 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
276290
await this._setDelay(this.showDelay);
277291

278292
this.open = true;
279-
this.toBeShown = true;
293+
this._toBeShown = true;
280294
const result = await this._toggleAnimation('open');
281-
this.toBeShown = false;
295+
this._toBeShown = false;
282296

283297
return result;
284298
};
@@ -289,10 +303,10 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
289303

290304
await this._setDelay(this.hideDelay);
291305

292-
this.toBeHidden = true;
306+
this._toBeHidden = true;
293307
const result = await this._toggleAnimation('close');
294-
this.open = false;
295-
this.toBeHidden = false;
308+
this.open = !result;
309+
this._toBeHidden = false;
296310

297311
return result;
298312
};
@@ -303,8 +317,7 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
303317
};
304318

305319
public showWithEvent = async () => {
306-
clearTimeout(this._timeoutId);
307-
if (this.toBeHidden) {
320+
if (this._toBeHidden) {
308321
await this._forceAnimationStop();
309322
return;
310323
}
@@ -320,8 +333,7 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
320333
};
321334

322335
public hideWithEvent = async () => {
323-
clearTimeout(this._timeoutId);
324-
if (this.toBeShown) {
336+
if (this._toBeShown) {
325337
await this._forceAnimationStop();
326338
return;
327339
}
@@ -337,6 +349,7 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
337349
};
338350

339351
protected [showOnTrigger] = () => {
352+
clearTimeout(this._timeoutId);
340353
this.showWithEvent();
341354
};
342355

@@ -346,12 +359,14 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
346359
if (related && (this.contains(related) || this._target?.contains(related)))
347360
return;
348361

349-
this.hideWithEvent();
362+
clearTimeout(this._timeoutId);
363+
this._timeoutId = setTimeout(() => this.hideWithEvent(), 180);
350364
};
351365

352366
protected override render() {
353367
return html`
354368
<igc-popover
369+
aria-hidden=${!this.open}
355370
.placement=${this.placement}
356371
.offset=${this.offset}
357372
.anchor=${this._target}
@@ -361,13 +376,7 @@ export default class IgcTooltipComponent extends EventEmitterMixin<
361376
flip
362377
shift
363378
>
364-
<div
365-
${ref(this._containerRef)}
366-
part="base"
367-
aria-hidden=${String(!this.open)}
368-
aria-live="polite"
369-
aria-atomic="true"
370-
>
379+
<div ${ref(this._containerRef)} part="base">
371380
${this.message ? html`${this.message}` : html`<slot></slot>`}
372381
${this.disableArrow ? nothing : html`<div id="arrow"></div>`}
373382
</div>

0 commit comments

Comments
 (0)