UNPKG

ngx-ellipsis-tool

Version:

Angular directive that automatically detects when text is truncated with ellipsis (...) and shows a tooltip with the full text — only when needed!

164 lines (159 loc) 7.06 kB
import * as i0 from '@angular/core'; import { Input, ChangeDetectionStrategy, Component, inject, ApplicationRef, EnvironmentInjector, DestroyRef, createComponent, HostListener, Directive } from '@angular/core'; import * as i1 from '@angular/common'; import { CommonModule } from '@angular/common'; class TooltipComponent { constructor() { this.text = ''; this.top = 0; this.left = 0; this.customClass = ''; } get formattedText() { return this.text.replace(/\n/g, '<br>'); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: TooltipComponent, isStandalone: true, selector: "app-tooltip", inputs: { text: "text", top: "top", left: "left", customClass: "customClass" }, ngImport: i0, template: ` <div class="custom-tooltip" [ngClass]="customClass" [style.top.px]="top" [style.left.px]="left" > <span [innerHTML]="formattedText"></span> </div> `, isInline: true, styles: [".custom-tooltip{background:#333;color:#fff;padding:4px 8px;border-radius:4px;font-size:12px;position:absolute;white-space:pre-line;z-index:10000;pointer-events:none;box-shadow:0 2px 8px #0000004d;transform:translateY(-100%);max-width:300px;word-wrap:break-word}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TooltipComponent, decorators: [{ type: Component, args: [{ selector: 'app-tooltip', standalone: true, imports: [CommonModule], template: ` <div class="custom-tooltip" [ngClass]="customClass" [style.top.px]="top" [style.left.px]="left" > <span [innerHTML]="formattedText"></span> </div> `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".custom-tooltip{background:#333;color:#fff;padding:4px 8px;border-radius:4px;font-size:12px;position:absolute;white-space:pre-line;z-index:10000;pointer-events:none;box-shadow:0 2px 8px #0000004d;transform:translateY(-100%);max-width:300px;word-wrap:break-word}\n"] }] }], propDecorators: { text: [{ type: Input }], top: [{ type: Input }], left: [{ type: Input }], customClass: [{ type: Input }] } }); class NgxEllipsisTooltipDirective { constructor(el) { this.el = el; this.placement = 'top'; this.delay = 300; this.tooltipClass = ''; this.appRef = inject(ApplicationRef); this.envInjector = inject(EnvironmentInjector); this.destroyRef = inject(DestroyRef); this.destroyRef.onDestroy(() => this.hideTooltip()); } onMouseEnter() { this.scheduleShowTooltip(); } onMouseLeave() { this.cancelShow(); this.hideTooltip(); } onClick() { // For mobile → show immediately on click this.cancelShow(); this.tryShowTooltip(); } onDocumentClick(event) { if (this.tooltipRef && !this.el.nativeElement.contains(event.target)) { this.hideTooltip(); } } scheduleShowTooltip() { this.cancelShow(); this.showTimeoutId = setTimeout(() => { this.tryShowTooltip(); }, this.delay); } cancelShow() { if (this.showTimeoutId) { clearTimeout(this.showTimeoutId); this.showTimeoutId = null; } } tryShowTooltip() { if (this.isTruncated()) { const text = this.tooltipText || this.el.nativeElement.textContent?.trim() || ''; const rect = this.el.nativeElement.getBoundingClientRect(); let top = rect.top + window.scrollY; let left = rect.left + window.scrollX; const elHeight = rect.height; if (this.placement === 'top') { top -= 8; } else { top += elHeight + 8; } this.showTooltip(text, left, top); } } isTruncated() { const el = this.el.nativeElement; return el.scrollWidth > el.clientWidth || el.scrollHeight > el.clientHeight; } showTooltip(text, left, top) { this.hideTooltip(); this.tooltipRef = createComponent(TooltipComponent, { environmentInjector: this.envInjector, hostElement: document.body }); this.tooltipRef.instance.text = text; this.tooltipRef.instance.left = left; this.tooltipRef.instance.top = top; this.tooltipRef.instance.customClass = this.tooltipClass; } hideTooltip() { if (this.tooltipRef) { this.tooltipRef.destroy(); this.tooltipRef = undefined; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgxEllipsisTooltipDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: NgxEllipsisTooltipDirective, isStandalone: true, selector: "[ngxEllipsisTooltip]", inputs: { tooltipText: "tooltipText", placement: "placement", delay: "delay", tooltipClass: "tooltipClass" }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "click": "onClick()", "document:click": "onDocumentClick($event)" } }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgxEllipsisTooltipDirective, decorators: [{ type: Directive, args: [{ selector: '[ngxEllipsisTooltip]', standalone: true }] }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { tooltipText: [{ type: Input }], placement: [{ type: Input }], delay: [{ type: Input }], tooltipClass: [{ type: Input }], onMouseEnter: [{ type: HostListener, args: ['mouseenter'] }], onMouseLeave: [{ type: HostListener, args: ['mouseleave'] }], onClick: [{ type: HostListener, args: ['click'] }], onDocumentClick: [{ type: HostListener, args: ['document:click', ['$event']] }] } }); /** * Generated bundle index. Do not edit. */ export { NgxEllipsisTooltipDirective }; //# sourceMappingURL=ngx-ellipsis-tool.mjs.map