UNPKG

@progress/kendo-angular-tooltip

Version:

Kendo UI Tooltip for Angular - A highly customizable and easily themeable tooltip from the creators developers trust for professional Angular components.

193 lines (192 loc) 8.13 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Directive, ElementRef, Input, NgZone, Renderer2 } from "@angular/core"; import { closest } from "@progress/kendo-angular-common"; import { PopupService } from "@progress/kendo-angular-popup"; import { filter, take } from "rxjs/operators"; import { closestBySelector } from "../utils"; import { PopoverDirectivesBase } from './directives-base'; import { PopoverService } from "./popover.service"; import * as i0 from "@angular/core"; import * as i1 from "@progress/kendo-angular-popup"; import * as i2 from "./popover.service"; /** * Represents the [`kendoPopoverContainer`](slug:configuration_popover#toc-popover-container) directive. * It is used to filter and target multiple elements, which should display a popover on interaction. * * @example * ```ts-no-run * <div kendoPopoverContainer [popover]="myPopover" filter=".has-popover"> * <button class="has-popover">Show Popover</button> * <button>Button Without Popover</button> * <button class="has-popover">Show Popover</button> * </div> * ``` */ export class PopoverContainerDirective extends PopoverDirectivesBase { wrapperEl; ngZone; popupService; renderer; popoverService; /** * Specifies a selector for the elements that should display a popover. * * The possible values include any valid query selector. * [See example](slug:configuration_popover#toc-popover-container) */ filter; constructor(wrapperEl, ngZone, popupService, renderer, popoverService) { super(ngZone, popupService, renderer); this.wrapperEl = wrapperEl; this.ngZone = ngZone; this.popupService = popupService; this.renderer = renderer; this.popoverService = popoverService; this._popoverService = this.popoverService; } /** * Shows the Popover. * * @param anchor&mdash;Specifies the element that will be used as an anchor. The Popover opens relative to that element. [See example]({% slug programmaticcontrol_popover %}) */ show(anchor) { if (this.popupRef) { return; } this.ngZone.run(() => { this.openPopup(anchor); }); this.popupRef.popupAnchorViewportLeave .pipe(take(1)) .subscribe(() => this.hide()); } /** * Toggles the visibility of the Popover. [See example]({% slug programmaticcontrol_popover %}) * * @param anchor&mdash;Specifies the element that will be used as an anchor. The Popover opens relative to that element. */ toggle(anchor) { const previousAnchor = this.popupRef && this.popupRef.content.instance.anchor; if (this.popupRef) { this.hide(); if (previousAnchor !== anchor) { this.show(anchor); } } else { this.show(anchor); } } subscribeClick() { if (this.disposeClickListener) { this.disposeClickListener(); } this.disposeClickListener = this.renderer.listen(document, 'click', (e) => { const filterElement = closestBySelector(e.target, this.filter); this.clickHandler(filterElement, e); }); } mouseenterHandler = (anchor) => { this.controlVisibility(anchor, true); }; mouseleaveHandler = (args) => { const anchor = args.anchor; if (this.isPrevented(anchor, false)) { return; } if (!this._hideSub) { this._hideSub = this.popoverService.hidePopover.subscribe((val) => { const [isPopoverHovered, , isOriginAnchor, currentAnchor] = val; if (!isPopoverHovered && !isOriginAnchor) { this.hide(); if (!isOriginAnchor && currentAnchor) { this.show(currentAnchor); } } }); } }; focusHandler = (anchor) => { this.controlVisibility(anchor, true); }; blurHandler = (args) => { const anchor = args.anchor; const event = args.domEvent; if (this.isPrevented(anchor, false)) { return; } // from anchor to popup focus check const isFocusInside = !!closest(event.relatedTarget, (node) => node.classList && node.classList.contains('k-popover')); if (!isFocusInside) { this.hide(); } if (!this._focusInsideSub) { // inside popup focus check this._focusInsideSub = this.popoverService.isFocusInsidePopover.pipe(filter(v => v !== null)).subscribe((val) => { if (!val && !isFocusInside) { this.hide(); } }); } }; subscribeToShowEvents(arr) { const filteredElements = Array.from(document.querySelectorAll(this.filter)); filteredElements.forEach((el) => { this.subs.add(this.renderer.listen(el, arr[0].name, () => { this.popoverService.emitAnchorState(true, el); arr[0].handler(el); })); this.subs.add(this.renderer.listen(el, arr[1].name, (e) => { this.popoverService.emitAnchorState(false, null); arr[1].handler({ anchor: el, domEvent: e }); })); }); } clickHandler(anchor, event) { const isInsidePopup = !!closest(event.target, (node) => node.classList && node.classList.contains('k-popup')); const popupRefAnchor = this.popupRef && this.popupRef.content.instance.anchor; const isOriginAnchor = !!closest(event.target, (node) => node === (popupRefAnchor ? popupRefAnchor : anchor)); if (this.showOn !== 'click' || isInsidePopup || (this.popupRef && isOriginAnchor)) { return; } if (!anchor && this.popupRef) { this.controlVisibility(anchor, false); return; } if (isOriginAnchor) { this.controlVisibility(anchor, true); } else if (this.popupRef) { this.controlVisibility(anchor, false); this.controlVisibility(anchor, true); } } controlVisibility(anchor, show) { if (this.isPrevented(anchor, show)) { return; } if (show) { this.show(anchor); } else { this.hide(); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PopoverContainerDirective, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: i1.PopupService }, { token: i0.Renderer2 }, { token: i2.PopoverService }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: PopoverContainerDirective, isStandalone: true, selector: "[kendoPopoverContainer]", inputs: { filter: "filter" }, providers: [PopoverService], exportAs: ["kendoPopoverContainer"], usesInheritance: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PopoverContainerDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoPopoverContainer]', exportAs: 'kendoPopoverContainer', providers: [PopoverService], standalone: true }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: i1.PopupService }, { type: i0.Renderer2 }, { type: i2.PopoverService }]; }, propDecorators: { filter: [{ type: Input }] } });