UNPKG

@taiga-ui/kit

Version:
255 lines (250 loc) • 12.8 kB
import { __extends, __decorate, __param } from 'tslib'; import { DOCUMENT } from '@angular/common'; import { Inject, ComponentFactoryResolver, Injector, ElementRef, Host, Optional, ChangeDetectorRef, NgZone, Renderer2, ViewContainerRef, Input, Directive, forwardRef, NgModule } from '@angular/core'; import { ALWAYS_TRUE_HANDLER, typedFromEvent, getNativeFocused, px, CHAR_ZERO_WIDTH_SPACE, CHAR_NO_BREAK_SPACE, TuiPortalService, TuiActiveZoneDirective, TuiDestroyService, TuiParentsScrollService } from '@taiga-ui/cdk'; import { TUI_DOCUMENT_OR_SHADOW_ROOT, TUI_ELEMENT_REF, TUI_DROPDOWN_DIRECTIVE, AbstractTuiDropdown, TuiDropdownBoxModule } from '@taiga-ui/core'; import { getWordRange } from '@taiga-ui/kit/utils/dom'; import { merge } from 'rxjs'; import { switchMapTo, takeUntil, map } from 'rxjs/operators'; // @dynamic var TuiDropdownSelectionDirective = /** @class */ (function (_super) { __extends(TuiDropdownSelectionDirective, _super); function TuiDropdownSelectionDirective(documentRef, componentFactoryResolver, injector, portalService, elementRef, activeZone, shadowRootRef, customElementRef, destroy$, refresh$, changeDetectorRef, ngZone, renderer, viewContainerRef) { var _this = _super.call(this, componentFactoryResolver, injector, portalService, customElementRef || elementRef, activeZone) || this; _this.refresh$ = refresh$; _this.changeDetectorRef = changeDetectorRef; _this.ngZone = ngZone; _this.renderer = renderer; _this.viewContainerRef = viewContainerRef; _this.position = "selection" /* Selection */; _this.visibilityHandler = ALWAYS_TRUE_HANDLER; _this.documentRef = shadowRootRef || documentRef; _this.range = _this.documentRef.createRange(); var nativeElement = _this.elementRef.nativeElement; merge(typedFromEvent(_this.documentRef, 'mouseup'), typedFromEvent(nativeElement, 'mousedown').pipe(switchMapTo(typedFromEvent(nativeElement, 'mousemove').pipe(takeUntil(typedFromEvent(_this.documentRef, 'mouseup'))))), typedFromEvent(nativeElement, 'keyup')) .pipe(map(function () { var active = getNativeFocused(_this.documentRef); var selection = _this.documentRef.getSelection(); if ((active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) && nativeElement.contains(active)) { return _this.veryVerySadInputFix(active); } return selection && selection.rangeCount ? selection.getRangeAt(0) : _this.range; }), takeUntil(destroy$)) .subscribe(function (range) { var contained = nativeElement.contains(range.commonAncestorContainer); _this.range = contained ? range : _this.range; var valid = contained && (!_this.visibilityHandler || _this.visibilityHandler(_this.range)); _this.toggleDropdownBox(valid || _this.inDropdown(range)); }); return _this; } TuiDropdownSelectionDirective_1 = TuiDropdownSelectionDirective; Object.defineProperty(TuiDropdownSelectionDirective.prototype, "tuiDropdownSelection", { set: function (handler) { if (!handler) { return; } var inHostAndValid = this.elementRef.nativeElement.contains(this.range.commonAncestorContainer) && handler(this.range); this.visibilityHandler = handler; this.toggleDropdownBox(inHostAndValid); }, enumerable: true, configurable: true }); Object.defineProperty(TuiDropdownSelectionDirective.prototype, "clientRect", { get: function () { var defaultView = this.documentRef.defaultView; var rangeRect = this.rangeRect; var frameElement = defaultView ? defaultView.frameElement : null; if (!frameElement) { return rangeRect; } var documentRect = frameElement.getBoundingClientRect(); return { top: rangeRect.top + documentRect.top, left: rangeRect.left + documentRect.left, right: rangeRect.left + documentRect.left + rangeRect.width, bottom: rangeRect.top + documentRect.top + rangeRect.height, width: rangeRect.width, height: rangeRect.height, }; }, enumerable: true, configurable: true }); TuiDropdownSelectionDirective.prototype.ngOnDestroy = function () { this.closeDropdownBox(); if (this.ghost) { this.renderer.removeChild(this.viewContainerRef.element.nativeElement, this.ghost); } }; Object.defineProperty(TuiDropdownSelectionDirective.prototype, "rangeRect", { /** * get ClientRect of current Range according to provided position */ get: function () { switch (this.position) { case "tag" /* Tag */: var commonAncestorContainer = this.range.commonAncestorContainer; var element = commonAncestorContainer.nodeType === Node.ELEMENT_NODE ? commonAncestorContainer : commonAncestorContainer.parentNode; return element.getBoundingClientRect(); case "word" /* Word */: return getWordRange(this.range).getBoundingClientRect(); default: return this.range.getBoundingClientRect(); } }, enumerable: true, configurable: true }); /** * Toggle dropdown visibility (has to be in ngZone.run because it could be initiated inside iframe in Editor) */ TuiDropdownSelectionDirective.prototype.toggleDropdownBox = function (visible) { var _this = this; this.ngZone.run(function () { if (visible) { _this.openDropdownBox(); } else { _this.closeDropdownBox(); } _this.changeDetectorRef.markForCheck(); }); }; /** * Check if Node is inside dropdown */ TuiDropdownSelectionDirective.prototype.boxContains = function (node) { return (!!this.dropdownBoxRef && this.dropdownBoxRef.location.nativeElement.contains(node)); }; /** * Check if given range is at leaset partially inside dropdown */ TuiDropdownSelectionDirective.prototype.inDropdown = function (range) { var startContainer = range.startContainer, endContainer = range.endContainer; var inDropdown = this.boxContains(range.commonAncestorContainer); var hostToDropdown = this.boxContains(endContainer) && this.elementRef.nativeElement.contains(startContainer); var dropdownToHost = this.boxContains(startContainer) && this.elementRef.nativeElement.contains(endContainer); return inDropdown || hostToDropdown || dropdownToHost; }; /** * Position invisible DIV and create Range similar to selected range inside input/textarea */ TuiDropdownSelectionDirective.prototype.veryVerySadInputFix = function (element) { var _a = this.ghost, ghost = _a === void 0 ? this.initGhost(element) : _a; var _b = element.getBoundingClientRect(), top = _b.top, left = _b.left, width = _b.width, height = _b.height; var selectionStart = element.selectionStart, selectionEnd = element.selectionEnd; var range = this.documentRef.createRange(); var hostRect = this.elementRef.nativeElement.getBoundingClientRect(); ghost.style.top = px(top - hostRect.top); ghost.style.left = px(left - hostRect.left); ghost.style.width = px(width); ghost.style.height = px(height); ghost.textContent = CHAR_ZERO_WIDTH_SPACE + element.value + CHAR_NO_BREAK_SPACE; range.setStart(ghost.firstChild, selectionStart || 0); range.setEnd(ghost.firstChild, selectionEnd || 0); return range; }; /** * Create an invisible DIV styled exactly like input/textarea element inside directive */ TuiDropdownSelectionDirective.prototype.initGhost = function (element) { var ghost = this.renderer.createElement('div'); var nativeElement = this.viewContainerRef.element.nativeElement; var _a = getComputedStyle(element), font = _a.font, letterSpacing = _a.letterSpacing, textTransform = _a.textTransform, padding = _a.padding; ghost.style.position = 'absolute'; ghost.style.pointerEvents = 'none'; ghost.style.opacity = '0'; ghost.style.whiteSpace = 'pre-wrap'; ghost.style.font = font; ghost.style.letterSpacing = letterSpacing; ghost.style.textTransform = textTransform; ghost.style.padding = padding; this.renderer.appendChild(nativeElement, ghost); this.ghost = ghost; return ghost; }; var TuiDropdownSelectionDirective_1; TuiDropdownSelectionDirective.ctorParameters = function () { return [ { type: Document, decorators: [{ type: Inject, args: [DOCUMENT,] }] }, { type: ComponentFactoryResolver, decorators: [{ type: Inject, args: [ComponentFactoryResolver,] }] }, { type: Injector, decorators: [{ type: Inject, args: [Injector,] }] }, { type: TuiPortalService, decorators: [{ type: Inject, args: [TuiPortalService,] }] }, { type: ElementRef, decorators: [{ type: Host }, { type: Inject, args: [ElementRef,] }] }, { type: TuiActiveZoneDirective, decorators: [{ type: Inject, args: [TuiActiveZoneDirective,] }, { type: Optional }] }, { type: Document, decorators: [{ type: Inject, args: [TUI_DOCUMENT_OR_SHADOW_ROOT,] }, { type: Optional }] }, { type: ElementRef, decorators: [{ type: Inject, args: [TUI_ELEMENT_REF,] }, { type: Optional }] }, { type: TuiDestroyService, decorators: [{ type: Inject, args: [TuiDestroyService,] }] }, { type: TuiParentsScrollService, decorators: [{ type: Inject, args: [TuiParentsScrollService,] }] }, { type: ChangeDetectorRef, decorators: [{ type: Inject, args: [ChangeDetectorRef,] }] }, { type: NgZone, decorators: [{ type: Inject, args: [NgZone,] }] }, { type: Renderer2, decorators: [{ type: Inject, args: [Renderer2,] }] }, { type: ViewContainerRef, decorators: [{ type: Inject, args: [ViewContainerRef,] }] } ]; }; __decorate([ Input() ], TuiDropdownSelectionDirective.prototype, "tuiDropdownSelection", null); __decorate([ Input('tuiDropdownSelectionPosition') ], TuiDropdownSelectionDirective.prototype, "position", void 0); TuiDropdownSelectionDirective = TuiDropdownSelectionDirective_1 = __decorate([ Directive({ selector: '[tuiDropdownSelection]:not(ng-container)', providers: [ { provide: TUI_DROPDOWN_DIRECTIVE, useExisting: forwardRef(function () { return TuiDropdownSelectionDirective_1; }), }, TuiParentsScrollService, TuiDestroyService, ], }), __param(0, Inject(DOCUMENT)), __param(1, Inject(ComponentFactoryResolver)), __param(2, Inject(Injector)), __param(3, Inject(TuiPortalService)), __param(4, Host()), __param(4, Inject(ElementRef)), __param(5, Inject(TuiActiveZoneDirective)), __param(5, Optional()), __param(6, Inject(TUI_DOCUMENT_OR_SHADOW_ROOT)), __param(6, Optional()), __param(7, Inject(TUI_ELEMENT_REF)), __param(7, Optional()), __param(8, Inject(TuiDestroyService)), __param(9, Inject(TuiParentsScrollService)), __param(10, Inject(ChangeDetectorRef)), __param(11, Inject(NgZone)), __param(12, Inject(Renderer2)), __param(13, Inject(ViewContainerRef)) ], TuiDropdownSelectionDirective); return TuiDropdownSelectionDirective; }(AbstractTuiDropdown)); var TuiDropdownSelectionModule = /** @class */ (function () { function TuiDropdownSelectionModule() { } TuiDropdownSelectionModule = __decorate([ NgModule({ imports: [TuiDropdownBoxModule], declarations: [TuiDropdownSelectionDirective], exports: [TuiDropdownSelectionDirective], }) ], TuiDropdownSelectionModule); return TuiDropdownSelectionModule; }()); /** * Generated bundle index. Do not edit. */ export { TuiDropdownSelectionDirective, TuiDropdownSelectionModule }; //# sourceMappingURL=taiga-ui-kit-directives-dropdown-selection.js.map