ngx-float-ui
Version:
ngx-float-ui is an Angular wrapper for Floating UI
829 lines (817 loc) • 36.3 kB
JavaScript
import { NgStyle, NgClass, CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { EventEmitter, Component, ViewEncapsulation, ChangeDetectionStrategy, ViewChild, HostListener, InjectionToken, Directive, Inject, Input, Output, NgModule } from '@angular/core';
import { autoUpdate, offset, flip, shift, limitShift, arrow, 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: "20.0.2", 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: "20.0.2", 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: "20.0.2", 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 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;
_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) => 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: "20.0.2", 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: "20.0.2", 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: "20.0.2", ngImport: i0, type: NgxFloatUiDirective, decorators: [{
type: Directive,
args: [{
selector: "[floatUi]",
exportAs: "floatUi",
standalone: true
}]
}], 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: "20.0.2", 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: "20.0.2", 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: "20.0.2", 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: "20.0.2", ngImport: i0, type: NgxFloatUiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
/** @nocollapse */ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.2", ngImport: i0, type: NgxFloatUiModule, imports: [CommonModule,
NgxFloatUiContentComponent,
NgxFloatUiDirective,
NgxFloatUiLooseDirective], exports: [NgxFloatUiContentComponent,
NgxFloatUiDirective,
NgxFloatUiLooseDirective] });
/** @nocollapse */ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: NgxFloatUiModule, providers: [
provideNgxFloatUiOptions()
], imports: [CommonModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.2", 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