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