UNPKG

ngx-float-ui

Version:

ngx-float-ui is an Angular wrapper for Floating UI

834 lines (821 loc) 36.4 kB
import { NgStyle, NgClass, CommonModule } from '@angular/common'; import * as i0 from '@angular/core'; import { EventEmitter, HostListener, ViewChild, ChangeDetectionStrategy, ViewEncapsulation, Component, InjectionToken, Input, Output, Inject, Directive, NgModule } from '@angular/core'; import { autoUpdate, offset, flip, shift, arrow, limitShift, autoPlacement, computePosition } from '@floating-ui/dom'; import { Subject, fromEvent, takeUntil, timer } from 'rxjs'; var NgxFloatUiPlacements; (function (NgxFloatUiPlacements) { NgxFloatUiPlacements["AUTO"] = "auto"; NgxFloatUiPlacements["AUTOSTART"] = "auto-start"; NgxFloatUiPlacements["AUTOEND"] = "auto-end"; NgxFloatUiPlacements["TOP"] = "top"; NgxFloatUiPlacements["BOTTOM"] = "bottom"; NgxFloatUiPlacements["LEFT"] = "left"; NgxFloatUiPlacements["RIGHT"] = "right"; NgxFloatUiPlacements["TOPSTART"] = "top-start"; NgxFloatUiPlacements["BOTTOMSTART"] = "bottom-start"; NgxFloatUiPlacements["LEFTSTART"] = "left-start"; NgxFloatUiPlacements["RIGHTSTART"] = "right-start"; NgxFloatUiPlacements["TOPEND"] = "top-end"; NgxFloatUiPlacements["BOTTOMEND"] = "bottom-end"; NgxFloatUiPlacements["LEFTEND"] = "left-end"; NgxFloatUiPlacements["RIGHTEND"] = "right-end"; })(NgxFloatUiPlacements || (NgxFloatUiPlacements = {})); var NgxFloatUiTriggers; (function (NgxFloatUiTriggers) { NgxFloatUiTriggers["click"] = "click"; NgxFloatUiTriggers["hover"] = "hover"; NgxFloatUiTriggers["mousedown"] = "mousedown"; NgxFloatUiTriggers["none"] = "none"; })(NgxFloatUiTriggers || (NgxFloatUiTriggers = {})); class NgxFloatUiContentComponent { elRef; _viewRef; _changeDetectorRef; static nextId = 0; get _dynamicArrowSides() { return { top: "left", right: "top", bottom: "left", left: "top" }; } get _sideAxis() { return { left: "x", top: "y", right: "x", bottom: "y" }; } get _staticArrowSides() { return { top: "bottom", right: "left", bottom: "top", left: "right" }; } ariaHidden; arrowColor = null; displayType; floatUiOptions = { disableAnimation: false, disableDefaultStyling: false, boundariesElement: "", trigger: NgxFloatUiTriggers.hover, positionFixed: false, appendToBody: false, popperModifiers: [] }; floatUiSwitch; floatUiViewRef; id = `ngx_float_ui_${++NgxFloatUiContentComponent.nextId}`; isMouseOver = !1; onHidden = new EventEmitter(); onUpdate; opacity; referenceObject; state; text; _destroy$ = new Subject(); _resizeCtrl$ = new Subject(); _styleId = `${this.id}_style`; constructor(elRef, _viewRef, _changeDetectorRef) { this.elRef = elRef; this._viewRef = _viewRef; this._changeDetectorRef = _changeDetectorRef; this._toggleVisibility(!1); } clean() { this.toggleVisibility(false); if (!this.floatUiSwitch) { return; } this.floatUiSwitch(); } extractAppliedClassListExpr(classList = []) { const klassList = Array.isArray(classList) ? classList : typeof classList === typeof "" ? classList.replace(/ /, "").split(",") : []; return klassList.reduce((acc, klass) => { acc[klass] = !0; return acc; }, {}); } hide() { if (this.floatUiSwitch) { this.floatUiSwitch(); } this.toggleVisibility(!1); this.onHidden.emit(); } ngOnDestroy() { this._destroy$.next(); this.clean(); if (this.floatUiOptions.appendTo && this.elRef && this.elRef.nativeElement && this.elRef.nativeElement.parentNode) { this._viewRef.detach(); this.elRef.nativeElement.parentNode.removeChild(this.elRef.nativeElement); } } onDocumentResize() { this.update(); } onMouseOver() { this.isMouseOver = true; } show() { if (!this.referenceObject) { return; } this._resizeCtrl$.next(); this._determineArrowColor(); this.floatUiSwitch = autoUpdate(this.referenceObject, this.floatUiViewRef.nativeElement, () => { this._computePosition(); }); fromEvent(document, "resize") .pipe(takeUntil(this._resizeCtrl$), takeUntil(this._destroy$)) .subscribe({ next: () => this.onDocumentResize() }); } showOnLeave() { this.isMouseOver = false; if (this.floatUiOptions.trigger !== NgxFloatUiTriggers.hover && !this.floatUiOptions.hideOnMouseLeave) { return; } this.hide(); } // Toggle visibility and detect changes - Run only after ngOnInit! toggleVisibility(state) { this._toggleVisibility(state); // tslint:disable-next-line:no-string-literal if (!this._changeDetectorRef["destroyed"]) { this._changeDetectorRef.detectChanges(); } } update() { this._computePosition(); } _computePosition() { const appendToParent = this.floatUiOptions.appendTo && document.querySelector(this.floatUiOptions.appendTo); if (appendToParent) { const parent = this.elRef.nativeElement.parentNode; if (parent !== appendToParent) { parent && parent.removeChild(this.elRef.nativeElement); appendToParent.appendChild(this.elRef.nativeElement); } } const arrowElement = this.elRef.nativeElement.querySelector(".float-ui-arrow"); const arrowLen = arrowElement.offsetWidth; // Get half the arrow box's hypotenuse length const floatingOffset = Math.sqrt(2 * arrowLen ** 2) / 2; const parsedAutoAlignment = (this.floatUiOptions.placement?.replace("auto-", "") || void 0); // Since "auto" doesn't really exist in floating-ui we pass undefined to have auto const parsedPlacement = !this.floatUiOptions.placement || this.floatUiOptions.placement.indexOf(NgxFloatUiPlacements.AUTO) === 0 ? void 0 : this.floatUiOptions.placement; const popperOptions = { placement: parsedPlacement, strategy: this.floatUiOptions.positionFixed ? "fixed" : "absolute", middleware: [ offset(floatingOffset), ...(this.floatUiOptions.preventOverflow ? [flip()] : []), shift({ limiter: limitShift() }), arrow({ element: arrowElement, padding: 4 }) ] }; // Since preventOverflow uses "flip" and "flip" can't be used with "autoPlacement" we get here only if both conditions are falsy if (!this.floatUiOptions.preventOverflow && !popperOptions.placement) { const boundariesElement = this.floatUiOptions.boundariesElement ? document.querySelector(this.floatUiOptions.boundariesElement) : this.referenceObject.parentElement; popperOptions.middleware.push(autoPlacement({ crossAxis: !0, alignment: parsedAutoAlignment, autoAlignment: this.floatUiOptions.placement === NgxFloatUiPlacements.AUTO, boundary: boundariesElement })); } computePosition(this.referenceObject, this.floatUiViewRef.nativeElement, { ...popperOptions }) .then(({ middlewareData, x, y, placement }) => { const side = placement.split("-")[0]; this.floatUiViewRef.nativeElement.setAttribute("data-float-ui-placement", side); if (middlewareData.arrow) { const staticArrowSide = this._staticArrowSides[side]; const dynamicArrowSide = this._dynamicArrowSides[side]; const dynamicSideAxis = this._sideAxis[dynamicArrowSide]; Object.assign(arrowElement.style, { top: "", bottom: "", left: "", right: "", [dynamicArrowSide]: middlewareData.arrow[dynamicSideAxis] != null ? `${middlewareData.arrow[dynamicSideAxis]}px` : "", [staticArrowSide]: `${-arrowLen / 2}px` }); } Object.assign(this.floatUiViewRef.nativeElement.style, { left: `${x}px`, top: `${y}px` }); this.toggleVisibility(!0); this.onUpdate?.(); }); } _createArrowSelector() { return `div#${this.id}.float-ui-container > .float-ui-arrow.ngxp__force-arrow`; } _determineArrowColor() { if (!this.floatUiOptions.styles || this.arrowColor) { return !1; } const ruleValue = this.floatUiOptions.styles["background-color"] || this.floatUiOptions.styles.backgroundColor; if (this.arrowColor === ruleValue) { return !1; } this.arrowColor = ruleValue; let $style = document.querySelector(`#${this._styleId}`); const styleContent = this.arrowColor ? `${this._createArrowSelector()}:before { background-color: ${this.arrowColor}; }` : ""; if (!$style) { $style = document.createElement("style"); $style.id = this._styleId; $style.setAttribute("type", "text/css"); document.head.appendChild($style); } // tslint:disable-next-line:no-string-literal if ($style["styleSheet"]) { // tslint:disable-next-line:no-string-literal $style["styleSheet"].cssText = styleContent; // This is required for IE8 and below. } else { $style.innerHTML = styleContent; } } _toggleVisibility(state) { this.displayType = ["none", "block"][+state]; this.opacity = +state; this.ariaHidden = `${!state}`; this.state = state; } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NgxFloatUiContentComponent, deps: [{ token: i0.ElementRef }, { token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); /** @nocollapse */ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: NgxFloatUiContentComponent, isStandalone: true, selector: "float-ui-content", host: { listeners: { "mouseover": "onMouseOver()", "mouseleave": "showOnLeave()" } }, viewQueries: [{ propertyName: "floatUiViewRef", first: true, predicate: ["floatUiViewRef"], descendants: true, static: true }], exportAs: ["ngxFloatUiContent"], ngImport: i0, template: "<div #floatUiViewRef\n\t [attr.id]=\"id\"\n\t [class.float-ui-container]=\"!floatUiOptions.disableDefaultStyling\"\n\t [class.float-ui-animation]=\"!floatUiOptions.disableAnimation\"\n\t [class.float-ui-fixed]=\"floatUiOptions.positionFixed\"\n\t [style.display]=\"displayType\"\n\t [style.opacity]=\"opacity\"\n\t [ngStyle]=\"floatUiOptions.styles\"\n\t [ngClass]=\"extractAppliedClassListExpr(floatUiOptions.applyClass)\"\n\t attr.aria-hidden=\"{{ariaHidden}}\"\n\t [attr.aria-describedby]=\"floatUiOptions.ariaDescribe || null\"\n\t attr.role=\"{{floatUiOptions.ariaRole}}\">\n\t@if (text) {\n\t\t<div\n\t\t\t\tclass=\"ngxp__inner\"\n\t\t\t\t[innerHTML]=\"text\">\n\t\t\t<ng-content></ng-content>\n\t\t</div>\n\t}\n\t@else {\n\t\t<div\n\t\t\t\tclass=\"ngxp__inner\">\n\t\t\t<ng-content></ng-content>\n\t\t</div>\n\t}\n\t<div class=\"float-ui-arrow\"\n\t\t [class.ngxp__force-arrow]=\"arrowColor\"\n\t\t [ngClass]=\"extractAppliedClassListExpr(floatUiOptions.applyArrowClass)\"></div>\n\n</div>\n", styles: ["float-ui-content{position:relative;display:block}.float-ui-container{display:none;position:absolute;border-radius:3px;border:1px solid grey;box-shadow:0 0 2px #00000080;padding:10px}.float-ui-container.float-ui-fixed{position:fixed}.float-ui-container.float-ui-animation{-webkit-animation:ngxp-fadeIn .15s ease-out;-moz-animation:ngxp-fadeIn .15s ease-out;-o-animation:ngxp-fadeIn .15s ease-out;animation:ngxp-fadeIn .15s ease-out;transition:transform .65s cubic-bezier(.43,.33,.14,1.01) 0s}.float-ui-container>.float-ui-arrow{position:absolute;width:10px;height:10px;z-index:-1;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}@-webkit-keyframes ngxp-fadeIn{0%{display:none;opacity:0}1%{display:block;opacity:0}to{display:block;opacity:1}}@keyframes ngxp-fadeIn{0%{display:none;opacity:0}1%{display:block;opacity:0}to{display:block;opacity:1}}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NgxFloatUiContentComponent, decorators: [{ type: Component, args: [{ selector: "float-ui-content", encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, exportAs: "ngxFloatUiContent", standalone: true, imports: [NgStyle, NgClass], template: "<div #floatUiViewRef\n\t [attr.id]=\"id\"\n\t [class.float-ui-container]=\"!floatUiOptions.disableDefaultStyling\"\n\t [class.float-ui-animation]=\"!floatUiOptions.disableAnimation\"\n\t [class.float-ui-fixed]=\"floatUiOptions.positionFixed\"\n\t [style.display]=\"displayType\"\n\t [style.opacity]=\"opacity\"\n\t [ngStyle]=\"floatUiOptions.styles\"\n\t [ngClass]=\"extractAppliedClassListExpr(floatUiOptions.applyClass)\"\n\t attr.aria-hidden=\"{{ariaHidden}}\"\n\t [attr.aria-describedby]=\"floatUiOptions.ariaDescribe || null\"\n\t attr.role=\"{{floatUiOptions.ariaRole}}\">\n\t@if (text) {\n\t\t<div\n\t\t\t\tclass=\"ngxp__inner\"\n\t\t\t\t[innerHTML]=\"text\">\n\t\t\t<ng-content></ng-content>\n\t\t</div>\n\t}\n\t@else {\n\t\t<div\n\t\t\t\tclass=\"ngxp__inner\">\n\t\t\t<ng-content></ng-content>\n\t\t</div>\n\t}\n\t<div class=\"float-ui-arrow\"\n\t\t [class.ngxp__force-arrow]=\"arrowColor\"\n\t\t [ngClass]=\"extractAppliedClassListExpr(floatUiOptions.applyArrowClass)\"></div>\n\n</div>\n", styles: ["float-ui-content{position:relative;display:block}.float-ui-container{display:none;position:absolute;border-radius:3px;border:1px solid grey;box-shadow:0 0 2px #00000080;padding:10px}.float-ui-container.float-ui-fixed{position:fixed}.float-ui-container.float-ui-animation{-webkit-animation:ngxp-fadeIn .15s ease-out;-moz-animation:ngxp-fadeIn .15s ease-out;-o-animation:ngxp-fadeIn .15s ease-out;animation:ngxp-fadeIn .15s ease-out;transition:transform .65s cubic-bezier(.43,.33,.14,1.01) 0s}.float-ui-container>.float-ui-arrow{position:absolute;width:10px;height:10px;z-index:-1;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}@-webkit-keyframes ngxp-fadeIn{0%{display:none;opacity:0}1%{display:block;opacity:0}to{display:block;opacity:1}}@keyframes ngxp-fadeIn{0%{display:none;opacity:0}1%{display:block;opacity:0}to{display:block;opacity:1}}\n"] }] }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }], propDecorators: { floatUiViewRef: [{ type: ViewChild, args: ["floatUiViewRef", { static: !0 }] }], onMouseOver: [{ type: HostListener, args: ["mouseover"] }], showOnLeave: [{ type: HostListener, args: ["mouseleave"] }] } }); const NGX_FLOAT_UI_DEFAULTS = new InjectionToken("NGX_FLOAT_UI_DEFAULTS"); /** * @private */ class NgxFloatUiUtils { /** Coerces a data-bound value (typically a string) to a boolean. */ static coerceBooleanProperty(value) { return value != null && `${value}` !== "false"; } } class NgxFloatUiDirective { _changeDetectorRef; _elementRef; _vcr; _popperDefaults; static nextId = 0; static baseOptions = { showDelay: 0, hideOnClickOutside: true, hideOnMouseLeave: false, hideOnScroll: false, appendTo: undefined, ariaRole: "popper", ariaDescribe: "", styles: {}, trigger: NgxFloatUiTriggers.click }; set applyClass(newValue) { if (newValue === this._applyClass) { return; } this._applyClass = newValue; this._checkExisting("applyClass", newValue); } get applyClass() { return this._applyClass; } set arrowClass(newValue) { if (newValue === this._arrowClass) { return; } this._arrowClass = newValue; if (this._content) { this._content.floatUiOptions.applyArrowClass = newValue; if (!this._shown) { return; } this._content.update(); } } get arrowClass() { return this._arrowClass; } set disabled(newValue) { if (newValue === this._disabled) { return; } this._disabled = !!newValue; if (this._shown) { this.hide(); } } get disabled() { return this._disabled; } set floatUi(newValue) { if (newValue === this._floatUi) { return; } this._floatUi = newValue; if (this._content) { if (typeof newValue === "string") { this._content.text = newValue; } else { this._content = newValue; } } } get floatUi() { return this._floatUi; } set hideOnClickOutside(newValue) { this._hideOnClickOutside = NgxFloatUiUtils.coerceBooleanProperty(newValue); } get hideOnClickOutside() { return this._hideOnClickOutside; } set placement(newValue) { this._placement = newValue; this._checkExisting("placement", newValue); } get placement() { return this._placement; } set preventOverflow(newValue) { this._preventOverflow = NgxFloatUiUtils.coerceBooleanProperty(newValue); this._checkExisting("preventOverflow", this._preventOverflow); } get preventOverflow() { return this._preventOverflow; } set showOnStart(newValue) { this._showOnStart = NgxFloatUiUtils.coerceBooleanProperty(newValue); } get showOnStart() { return this._showOnStart; } appendTo; ariaDescribe; ariaRole; boundariesElement; disableAnimation; disableStyle; hideOnMouseLeave; hideOnScroll; hideTimeout = 0; onHidden = new EventEmitter(); onShown = new EventEmitter(); onUpdate = new EventEmitter(); positionFixed; showDelay; showTrigger; styles; targetElement; timeoutAfterShow = 0; _applyClass; _arrowClass; _content; _contentClass = NgxFloatUiContentComponent; _contentRef; _destroy$ = new Subject(); _disabled; _floatUi; _globalEventListenersCtrl$ = new Subject(); _hideOnClickOutside = !0; // @internal _id = `ngx_float_ui_directive_${++NgxFloatUiDirective.nextId}`; _placement; _preventOverflow; _scheduledHideTimeoutCtrl$ = new Subject(); _scheduledShowTimeoutCtrl$ = new Subject(); _shown = !1; _showOnStart = !1; constructor(_changeDetectorRef, _elementRef, _vcr, _popperDefaults = {}) { this._changeDetectorRef = _changeDetectorRef; this._elementRef = _elementRef; this._vcr = _vcr; this._popperDefaults = _popperDefaults; NgxFloatUiDirective.baseOptions = { ...NgxFloatUiDirective.baseOptions, ...this._popperDefaults }; } static assignDefined(target, ...sources) { for (const source of sources) { for (const key of Object.keys(source)) { const val = source[key]; if (val !== undefined) { target[key] = val; } } } return target; } applyTriggerListeners() { switch (this.showTrigger) { case NgxFloatUiTriggers.click: this._addListener("click", this.toggle.bind(this)); break; case NgxFloatUiTriggers.mousedown: this._addListener("mousedown", this.toggle.bind(this)); break; case NgxFloatUiTriggers.hover: this._addListener("mouseenter", this.scheduledShow.bind(this, this.showDelay)); ["touchend", "touchcancel", "mouseleave"].forEach((eventName) => { this._addListener(eventName, this.scheduledHide.bind(this, null, this.hideTimeout)); }); break; } if (this.showTrigger !== NgxFloatUiTriggers.hover && this.hideOnMouseLeave) { ["touchend", "touchcancel", "mouseleave"].forEach((eventName) => { this._addListener(eventName, this.scheduledHide.bind(this, null, this.hideTimeout)); }); } } getRefElement() { return this.targetElement || this._elementRef.nativeElement; } hide() { if (this.disabled) { return; } if (!this._shown) { this._scheduledShowTimeoutCtrl$.next(); return; } this._shown = false; if (this._contentRef) { this._contentRef.instance.hide(); } else { this._content.hide(); } this.onHidden.emit(this); this._globalEventListenersCtrl$.next(); } hideOnClickOutsideHandler($event) { if (this.disabled || !this.hideOnClickOutside || $event.target === this._content.elRef.nativeElement || this._content.elRef.nativeElement.contains($event.target)) { return; } this.scheduledHide($event, this.hideTimeout); } hideOnScrollHandler($event) { if (this.disabled || !this.hideOnScroll) { return; } this.scheduledHide($event, this.hideTimeout); } ngOnDestroy() { this._destroy$.next(); this._destroy$.complete(); this._content && this._content.clean(); } ngOnInit() { if (typeof this.floatUi === "string") { this._content = this._constructContent(); this._content.text = this.floatUi; } else if (typeof this.floatUi === typeof void 0) { this._content = this._constructContent(); this._content.text = ""; } else { this._content = this.floatUi; } const popperRef = this._content; popperRef.referenceObject = this.getRefElement(); this._setContentProperties(popperRef); this._setDefaults(); this.applyTriggerListeners(); if (this.showOnStart) { this.scheduledShow(); } } scheduledHide($event = null, delay = this.hideTimeout) { if (this.disabled) { return; } this._scheduledHideTimeoutCtrl$.next(); timer(delay) .pipe(takeUntil(this._scheduledHideTimeoutCtrl$), takeUntil(this._destroy$)) .subscribe({ next: () => { // TODO: check const toElement = $event ? $event.toElement : null; const popperContentView = this._content.floatUiViewRef ? this._content.floatUiViewRef.nativeElement : false; if (!popperContentView || popperContentView === toElement || popperContentView.contains(toElement) || (this.floatUi && this.floatUi.isMouseOver)) { return; } this.hide(); this._applyChanges(); } }); } scheduledShow(delay = this.showDelay) { if (this.disabled) { return; } this._scheduledHideTimeoutCtrl$.next(); timer(delay) .pipe(takeUntil(this._scheduledShowTimeoutCtrl$), takeUntil(this._destroy$)) .subscribe({ next: () => { this.show(); this._applyChanges(); } }); } show() { if (this._shown) { this._scheduledHideTimeoutCtrl$.next(); return; } this._shown = true; const popperRef = this._content; const element = this.getRefElement(); if (popperRef.referenceObject !== element) { popperRef.referenceObject = element; } this._setContentProperties(popperRef); popperRef.show(); this.onShown.emit(this); if (this.timeoutAfterShow > 0) { this.scheduledHide(null, this.timeoutAfterShow); } fromEvent(document, "click") .pipe(takeUntil(this._globalEventListenersCtrl$), takeUntil(this._destroy$)) .subscribe({ next: (e) => { return this.hideOnClickOutsideHandler(e); } }); fromEvent(this._getScrollParent(this.getRefElement()), "scroll") .pipe(takeUntil(this._globalEventListenersCtrl$), takeUntil(this._destroy$)) .subscribe({ next: (e) => { this.hideOnScrollHandler(e); } }); } toggle() { if (this.disabled) { return; } this._shown ? this.scheduledHide(null, this.hideTimeout) : this.scheduledShow(); } _addListener(eventName, cb) { fromEvent(this._elementRef.nativeElement, eventName) .pipe(takeUntil(this._destroy$)) .subscribe({ next: cb }); } _applyChanges() { this._changeDetectorRef.markForCheck(); this._changeDetectorRef.detectChanges(); } _checkExisting(key, newValue) { if (this._content) { this._content.floatUiOptions[key] = newValue; if (!this._shown) { return; } this._content.update(); } } _constructContent() { this._contentRef = this._vcr.createComponent(this._contentClass); return this._contentRef.instance; } _getScrollParent(node) { const isElement = node instanceof HTMLElement; const overflowY = isElement && window.getComputedStyle(node).overflowY; const isScrollable = overflowY !== "visible" && overflowY !== "hidden"; if (!node) { return null; } else if (isScrollable && node.scrollHeight > node.clientHeight) { return node; } return this._getScrollParent(node.parentNode) || document; } _onPopperUpdate() { this.onUpdate.emit(); } _setContentProperties(popperRef) { popperRef.floatUiOptions = NgxFloatUiDirective.assignDefined(popperRef.floatUiOptions, NgxFloatUiDirective.baseOptions, { showDelay: this.showDelay, disableAnimation: this.disableAnimation, disableDefaultStyling: this.disableStyle, placement: this.placement, boundariesElement: this.boundariesElement, trigger: this.showTrigger, positionFixed: this.positionFixed, ariaDescribe: this.ariaDescribe, ariaRole: this.ariaRole, applyClass: this.applyClass, applyArrowClass: this.arrowClass, hideOnMouseLeave: this.hideOnMouseLeave, styles: this.styles, appendTo: this.appendTo, preventOverflow: this.preventOverflow }); popperRef.onUpdate = this._onPopperUpdate.bind(this); popperRef.onHidden .pipe(takeUntil(this._destroy$)) .subscribe(this.hide.bind(this)); } _setDefaults() { ["showDelay", "hideOnScroll", "hideOnMouseLeave", "hideOnClickOutside", "ariaRole", "ariaDescribe"].forEach((key) => { this[key] = this[key] === void 0 ? NgxFloatUiDirective.baseOptions[key] : this[key]; }); this.showTrigger = this.showTrigger || NgxFloatUiDirective.baseOptions.trigger; this.styles = this.styles === void 0 ? { ...NgxFloatUiDirective.baseOptions.styles } : this.styles; } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NgxFloatUiDirective, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.ViewContainerRef }, { token: NGX_FLOAT_UI_DEFAULTS }], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.3", type: NgxFloatUiDirective, isStandalone: true, selector: "[floatUi]", inputs: { applyClass: "applyClass", arrowClass: "arrowClass", disabled: "disabled", floatUi: "floatUi", hideOnClickOutside: "hideOnClickOutside", placement: "placement", preventOverflow: "preventOverflow", showOnStart: "showOnStart", appendTo: "appendTo", ariaDescribe: "ariaDescribe", ariaRole: "ariaRole", boundariesElement: "boundariesElement", disableAnimation: "disableAnimation", disableStyle: "disableStyle", hideOnMouseLeave: "hideOnMouseLeave", hideOnScroll: "hideOnScroll", hideTimeout: "hideTimeout", positionFixed: "positionFixed", showDelay: "showDelay", showTrigger: "showTrigger", styles: "styles", targetElement: "targetElement", timeoutAfterShow: "timeoutAfterShow" }, outputs: { onHidden: "onHidden", onShown: "onShown", onUpdate: "onUpdate" }, exportAs: ["floatUi"], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NgxFloatUiDirective, decorators: [{ type: Directive, args: [{ selector: "[floatUi]", exportAs: "floatUi" }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{ type: Inject, args: [NGX_FLOAT_UI_DEFAULTS] }] }], propDecorators: { applyClass: [{ type: Input }], arrowClass: [{ type: Input }], disabled: [{ type: Input }], floatUi: [{ type: Input }], hideOnClickOutside: [{ type: Input }], placement: [{ type: Input }], preventOverflow: [{ type: Input }], showOnStart: [{ type: Input }], appendTo: [{ type: Input }], ariaDescribe: [{ type: Input }], ariaRole: [{ type: Input }], boundariesElement: [{ type: Input }], disableAnimation: [{ type: Input }], disableStyle: [{ type: Input }], hideOnMouseLeave: [{ type: Input }], hideOnScroll: [{ type: Input }], hideTimeout: [{ type: Input }], onHidden: [{ type: Output }], onShown: [{ type: Output }], onUpdate: [{ type: Output }], positionFixed: [{ type: Input }], showDelay: [{ type: Input }], showTrigger: [{ type: Input }], styles: [{ type: Input }], targetElement: [{ type: Input }], timeoutAfterShow: [{ type: Input }] } }); class NgxFloatUiLooseDirective extends NgxFloatUiDirective { set floatUiLoose(newValue) { this.floatUi = newValue; } set loosePlacement(newValue) { this.placement = newValue; } set looseTrigger(newValue) { this.showTrigger = newValue; } constructor(changeDetectorRef, elementRef, vcr, popperDefaults = {}) { super(changeDetectorRef, elementRef, vcr, popperDefaults); } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NgxFloatUiLooseDirective, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.ViewContainerRef }, { token: NGX_FLOAT_UI_DEFAULTS }], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.3", type: NgxFloatUiLooseDirective, isStandalone: true, selector: "[floatUiLoose]", inputs: { floatUiLoose: "floatUiLoose", loosePlacement: "loosePlacement", looseTrigger: "looseTrigger" }, exportAs: ["floatUiLoose"], usesInheritance: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NgxFloatUiLooseDirective, decorators: [{ type: Directive, args: [{ selector: "[floatUiLoose]", exportAs: "floatUiLoose", standalone: true }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{ type: Inject, args: [NGX_FLOAT_UI_DEFAULTS] }] }], propDecorators: { floatUiLoose: [{ type: Input }], loosePlacement: [{ type: Input }], looseTrigger: [{ type: Input }] } }); function provideNgxFloatUiOptions(config = {}) { return [ { provide: NGX_FLOAT_UI_DEFAULTS, useValue: config }, ]; } class NgxFloatUiModule { static forRoot(popperBaseOptions) { return { ngModule: NgxFloatUiModule, providers: [ provideNgxFloatUiOptions(popperBaseOptions) ] }; } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NgxFloatUiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); /** @nocollapse */ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.3", ngImport: i0, type: NgxFloatUiModule, imports: [CommonModule, NgxFloatUiContentComponent, NgxFloatUiDirective, NgxFloatUiLooseDirective], exports: [NgxFloatUiContentComponent, NgxFloatUiDirective, NgxFloatUiLooseDirective] }); /** @nocollapse */ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NgxFloatUiModule, providers: [ provideNgxFloatUiOptions() ], imports: [CommonModule] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NgxFloatUiModule, decorators: [{ type: NgModule, args: [{ imports: [ CommonModule, NgxFloatUiContentComponent, NgxFloatUiDirective, NgxFloatUiLooseDirective ], exports: [ NgxFloatUiContentComponent, NgxFloatUiDirective, NgxFloatUiLooseDirective ], providers: [ provideNgxFloatUiOptions() ] }] }] }); /* * Public API Surface of ngx-float-ui */ // Components /** * Generated bundle index. Do not edit. */ export { NgxFloatUiContentComponent, NgxFloatUiDirective, NgxFloatUiLooseDirective, NgxFloatUiModule, NgxFloatUiPlacements, NgxFloatUiTriggers, provideNgxFloatUiOptions }; //# sourceMappingURL=ngx-float-ui.mjs.map