From 4589146e312b8b6b16213249330e55544eb08420 Mon Sep 17 00:00:00 2001 From: Nino Righi Date: Wed, 26 Nov 2025 20:08:11 +0000 Subject: [PATCH] Merged PR 2056: fix(ui-tooltip): Integrated CloseOnScrollDirective to close tooltip on scrolling fix(ui-tooltip): Integrated CloseOnScrollDirective to close tooltip on scrolling Ref: #5510 --- libs/ui/tooltip/src/lib/tooltip.directive.ts | 46 ++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/libs/ui/tooltip/src/lib/tooltip.directive.ts b/libs/ui/tooltip/src/lib/tooltip.directive.ts index daea7c248..cddfff2d3 100644 --- a/libs/ui/tooltip/src/lib/tooltip.directive.ts +++ b/libs/ui/tooltip/src/lib/tooltip.directive.ts @@ -12,10 +12,12 @@ import { inject, input, OnDestroy, + signal, TemplateRef, ViewContainerRef, } from '@angular/core'; import { TooltipComponent } from './tooltip.component'; +import { CloseOnScrollDirective } from '@isa/ui/layout'; /** * Defines the trigger events for the tooltip. @@ -57,12 +59,19 @@ export type TooltipTrigger = */ @Directive({ selector: '[uiTooltip]', + hostDirectives: [ + { + directive: CloseOnScrollDirective, + outputs: ['closeOnScroll'], + }, + ], host: { '(click)': 'onClickEvent($event)', '(mouseenter)': 'onMouseEnter()', '(mouseleave)': 'onMouseLeave()', '(focus)': 'onFocusEvent()', '(blur)': 'onBlurEvent()', + '(closeOnScroll)': 'onScrollClose()', 'tabindex': '0', }, standalone: true, @@ -73,10 +82,12 @@ export class TooltipDirective implements OnDestroy { #elementRef = inject(ElementRef); #viewContainerRef = inject(ViewContainerRef); #positionBuilder = inject(OverlayPositionBuilder); + #closeOnScroll = inject(CloseOnScrollDirective, { self: true }); #overlayRef: OverlayRef | null = null; #tooltipInstance: TooltipComponent | null = null; #openTrigger: TooltipTrigger | null = null; // Tracks which trigger opened the tooltip + #isOpen = signal(false); // Internal signal to track open state for CloseOnScrollDirective // Distance between tooltip and anchor element readonly #offset = 8; // 0.5rem = 8px @@ -124,6 +135,13 @@ export class TooltipDirective implements OnDestroy { this.#tooltipInstance.variant.set(variantValue); } }); + + // Configure CloseOnScrollDirective: activate when tooltip is open (any trigger) + effect(() => { + const isOpen = this.#isOpen(); + // Activate scroll-close behavior whenever tooltip is open + this.#closeOnScroll.closeOnScrollWhen.set(isOpen); + }); } /** @@ -230,6 +248,13 @@ export class TooltipDirective implements OnDestroy { if (variantValue !== undefined) { this.#tooltipInstance.variant.set(variantValue); } + + // Update open state for CloseOnScrollDirective + // Set exclude element first, then activate + this.#closeOnScroll.closeOnScrollExclude.set( + this.#overlayRef.overlayElement, + ); + this.#isOpen.set(true); } /** @@ -264,6 +289,9 @@ export class TooltipDirective implements OnDestroy { this.#overlayRef = null; this.#tooltipInstance = null; this.#openTrigger = null; + + // Update open state for CloseOnScrollDirective + this.#isOpen.set(false); } /** @@ -341,6 +369,24 @@ export class TooltipDirective implements OnDestroy { } } + /** + * Handles the scroll close event from CloseOnScrollDirective. + * Closes the tooltip when user scrolls while tooltip is open. + * @internal + */ + onScrollClose() { + // Force close regardless of trigger since scroll should always close + if (this.#overlayRef) { + this.#isOpen.set(false); + this.#closeOnScroll.closeOnScrollExclude.set(undefined); + this.#overlayRef.detach(); + this.#overlayRef.dispose(); + this.#overlayRef = null; + this.#tooltipInstance = null; + this.#openTrigger = null; + } + } + /** * Cleans up the tooltip when the directive is destroyed. * Ensures the tooltip is hidden to prevent memory leaks.