@taiga-ui/kit
Version:
Taiga UI Angular main components kit
193 lines (187 loc) • 8.42 kB
JavaScript
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