UNPKG

@taiga-ui/kit

Version:
193 lines (187 loc) • 8.42 kB
import { __decorate, __param } from 'tslib'; import { ElementRef, Inject, Renderer2, Input, ViewChild, HostBinding, HostListener, Component, ChangeDetectionStrategy, ViewContainerRef, NgZone, Directive, NgModule } from '@angular/core'; import { typedFromEvent, isCurrentTarget, tuiDefaultProp, tuiPure, CHAR_ELLIPSIS, tuiZonefree, TuiDestroyService, TuiResizeModule } from '@taiga-ui/cdk'; import { PolymorpheusOutletComponent, PolymorpheusModule } from '@tinkoff/ng-polymorpheus'; import { BehaviorSubject, of, Observable } from 'rxjs'; import { startWith, pairwise, switchMap, filter, mapTo, map, takeUntil } from 'rxjs/operators'; import { DOCUMENT, CommonModule } from '@angular/common'; import { TuiHintModule } from '@taiga-ui/core'; import { ANIMATION_FRAME, CSS } from '@ng-web-apis/common'; import { setRangeOffset } from '@taiga-ui/kit/utils/dom'; let TuiLineClampComponent = class TuiLineClampComponent { constructor(elementRef, renderer) { this.elementRef = elementRef; this.lineHeight = 24; this.content = ''; this.linesLimit$ = new BehaviorSubject(1); this.initialized = false; // Skipping initial transition setTimeout(() => { renderer.addClass(this.elementRef.nativeElement, '_initialized'); }); } set linesLimit(linesLimit) { this.linesLimit$.next(linesLimit); } get lineClamp$() { return this.linesLimit$.pipe(startWith(1), pairwise(), switchMap(([prev, next]) => next >= prev ? of(next) : typedFromEvent(this.elementRef.nativeElement, 'transitionend').pipe(filter(isCurrentTarget), mapTo(next)))); } get overflown() { if (!this.outlet) { return false; } const { scrollHeight, scrollWidth } = this.outlet.nativeElement; const { clientHeight, clientWidth } = this.elementRef.nativeElement; // 4px buffer for IE/Edge incorrectly rounding scrollHeight return scrollHeight - clientHeight > 4 || scrollWidth - clientWidth > 0; } get computedContent() { return this.overflown ? this.content : ''; } get oneLine() { return this.linesLimit$.value === 1; } get maxHeight() { return this.initialized ? this.lineHeight * this.linesLimit$.value : null; } get height() { return !this.outlet ? 0 : this.outlet.nativeElement.scrollHeight + 4 || null; } ngAfterViewInit() { this.initialized = true; } // Change detection markForCheck() { } }; TuiLineClampComponent.ctorParameters = () => [ { type: ElementRef, decorators: [{ type: Inject, args: [ElementRef,] }] }, { type: Renderer2, decorators: [{ type: Inject, args: [Renderer2,] }] } ]; __decorate([ Input(), tuiDefaultProp() ], TuiLineClampComponent.prototype, "linesLimit", null); __decorate([ Input(), tuiDefaultProp() ], TuiLineClampComponent.prototype, "lineHeight", void 0); __decorate([ Input(), tuiDefaultProp() ], TuiLineClampComponent.prototype, "content", void 0); __decorate([ ViewChild(PolymorpheusOutletComponent, { read: ElementRef }) ], TuiLineClampComponent.prototype, "outlet", void 0); __decorate([ tuiPure ], TuiLineClampComponent.prototype, "lineClamp$", null); __decorate([ HostBinding('style.maxHeight.px') ], TuiLineClampComponent.prototype, "maxHeight", null); __decorate([ HostBinding('style.height.px') ], TuiLineClampComponent.prototype, "height", null); __decorate([ HostListener('mouseenter') ], TuiLineClampComponent.prototype, "markForCheck", null); TuiLineClampComponent = __decorate([ Component({ selector: 'tui-line-clamp', template: "<div\n polymorpheus-outlet\n class=\"wrapper\"\n lineClamp\n tuiHintId=\"unnecessary\"\n tuiHintMode=\"overflow\"\n [tuiHint]=\"computedContent\"\n [class.wrapper_ellipsis]=\"oneLine\"\n [style.-webkit-line-clamp]=\"lineClamp$ | async\"\n [content]=\"content\"\n (tuiResize)=\"markForCheck()\"\n></div>\n", changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{position:relative;display:block;overflow:hidden}:host._initialized{transition-property:max-height;transition-duration:.3s;transition-timing-function:ease-in-out}.wrapper{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden}.wrapper_ellipsis{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}"] }), __param(0, Inject(ElementRef)), __param(1, Inject(Renderer2)) ], TuiLineClampComponent); const HIDDEN_LEFT = -200; // @dynamic let TuiLineClampDirective = class TuiLineClampDirective { constructor(component, viewContainerRef, documentRef, renderer, ngZone, { nativeElement }, destroy$, animationFrame$, /** * TODO: remove "any" in new TS version; https://github.com/ng-web-apis/common/pull/6 */ cssRef) { if (cssRef.supports('-webkit-line-clamp', '1') || !(nativeElement.parentElement instanceof HTMLElement)) { return; } const range = documentRef.createRange(); const ellipsis = renderer.createElement('div'); const { parentElement } = nativeElement; const { style } = ellipsis; style.position = 'absolute'; style.bottom = '0'; style.left = `${HIDDEN_LEFT}px`; ellipsis.textContent = CHAR_ELLIPSIS; viewContainerRef.element.nativeElement.appendChild(ellipsis); animationFrame$ .pipe(map(() => { // 4px buffer for IE/Edge incorrectly rounding scrollHeight if (component.oneLine || nativeElement.scrollHeight - parentElement.clientHeight < 4) { return HIDDEN_LEFT; } let result = 0; const length = nativeElement.textContent ? nativeElement.textContent.length : 0; for (let char = 0; char < length - 2; char++) { setRangeOffset(range, nativeElement, char, 'setStart'); setRangeOffset(range, nativeElement, char + 1, 'setEnd'); const rangeRect = range.getBoundingClientRect(); const clientRect = parentElement.getBoundingClientRect(); if (Math.round(rangeRect.top - clientRect.bottom) >= 0) { break; } result = rangeRect.right - clientRect.left; } return result; }), tuiZonefree(ngZone), takeUntil(destroy$)) .subscribe(left => { style.left = `${left}px`; }); } }; TuiLineClampDirective.ctorParameters = () => [ { type: TuiLineClampComponent, decorators: [{ type: Inject, args: [TuiLineClampComponent,] }] }, { type: ViewContainerRef, decorators: [{ type: Inject, args: [ViewContainerRef,] }] }, { type: Document, decorators: [{ type: Inject, args: [DOCUMENT,] }] }, { type: Renderer2, decorators: [{ type: Inject, args: [Renderer2,] }] }, { type: NgZone, decorators: [{ type: Inject, args: [NgZone,] }] }, { type: ElementRef, decorators: [{ type: Inject, args: [ElementRef,] }] }, { type: TuiDestroyService, decorators: [{ type: Inject, args: [TuiDestroyService,] }] }, { type: Observable, decorators: [{ type: Inject, args: [ANIMATION_FRAME,] }] }, { type: undefined, decorators: [{ type: Inject, args: [CSS,] }] } ]; TuiLineClampDirective = __decorate([ Directive({ selector: '[lineClamp]', providers: [TuiDestroyService], }), __param(0, Inject(TuiLineClampComponent)), __param(1, Inject(ViewContainerRef)), __param(2, Inject(DOCUMENT)), __param(3, Inject(Renderer2)), __param(4, Inject(NgZone)), __param(5, Inject(ElementRef)), __param(6, Inject(TuiDestroyService)), __param(7, Inject(ANIMATION_FRAME)), __param(8, Inject(CSS)) ], TuiLineClampDirective); let TuiLineClampModule = class TuiLineClampModule { }; TuiLineClampModule = __decorate([ NgModule({ imports: [CommonModule, PolymorpheusModule, TuiHintModule, TuiResizeModule], declarations: [TuiLineClampComponent, TuiLineClampDirective], exports: [TuiLineClampComponent], }) ], TuiLineClampModule); /** * Generated bundle index. Do not edit. */ export { TuiLineClampComponent, TuiLineClampDirective, TuiLineClampModule }; //# sourceMappingURL=taiga-ui-kit-components-line-clamp.js.map