mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2718 lines
89 KiB
2718 lines
89 KiB
import * as i0 from '@angular/core';
|
|
import { DOCUMENT, NgZone, inject, Injector, Injectable, RendererFactory2, Component, ChangeDetectionStrategy, ViewEncapsulation, afterNextRender, ElementRef, InjectionToken, ApplicationRef, Renderer2, ANIMATION_MODULE_TYPE, EnvironmentInjector, Directive, EventEmitter, TemplateRef, ViewContainerRef, booleanAttribute, Input, Output, NgModule } from '@angular/core';
|
|
import { Location } from '@angular/common';
|
|
import { Platform } from './_platform-chunk.mjs';
|
|
import { _getEventTarget } from './_shadow-dom-chunk.mjs';
|
|
import { _isTestEnvironment } from './_test-environment-chunk.mjs';
|
|
import { _CdkPrivateStyleLoader } from './_style-loader-chunk.mjs';
|
|
import { Subject, Subscription } from 'rxjs';
|
|
import { coerceCssPixelValue } from './_css-pixel-value-chunk.mjs';
|
|
import { coerceArray } from './_array-chunk.mjs';
|
|
import { ViewportRuler, ScrollDispatcher, ScrollingModule } from './scrolling.mjs';
|
|
import { DomPortalOutlet, TemplatePortal, PortalModule } from './portal.mjs';
|
|
import { supportsScrollBehavior } from './_scrolling-chunk.mjs';
|
|
import { filter, takeWhile } from 'rxjs/operators';
|
|
import { _IdGenerator } from './_id-generator-chunk.mjs';
|
|
import { Directionality } from './_directionality-chunk.mjs';
|
|
import { ESCAPE } from './_keycodes-chunk.mjs';
|
|
import { hasModifierKey } from './keycodes.mjs';
|
|
import { BidiModule } from './bidi.mjs';
|
|
|
|
const scrollBehaviorSupported = supportsScrollBehavior();
|
|
function createBlockScrollStrategy(injector) {
|
|
return new BlockScrollStrategy(injector.get(ViewportRuler), injector.get(DOCUMENT));
|
|
}
|
|
class BlockScrollStrategy {
|
|
_viewportRuler;
|
|
_previousHTMLStyles = {
|
|
top: '',
|
|
left: ''
|
|
};
|
|
_previousScrollPosition;
|
|
_isEnabled = false;
|
|
_document;
|
|
constructor(_viewportRuler, document) {
|
|
this._viewportRuler = _viewportRuler;
|
|
this._document = document;
|
|
}
|
|
attach() {}
|
|
enable() {
|
|
if (this._canBeEnabled()) {
|
|
const root = this._document.documentElement;
|
|
this._previousScrollPosition = this._viewportRuler.getViewportScrollPosition();
|
|
this._previousHTMLStyles.left = root.style.left || '';
|
|
this._previousHTMLStyles.top = root.style.top || '';
|
|
root.style.left = coerceCssPixelValue(-this._previousScrollPosition.left);
|
|
root.style.top = coerceCssPixelValue(-this._previousScrollPosition.top);
|
|
root.classList.add('cdk-global-scrollblock');
|
|
this._isEnabled = true;
|
|
}
|
|
}
|
|
disable() {
|
|
if (this._isEnabled) {
|
|
const html = this._document.documentElement;
|
|
const body = this._document.body;
|
|
const htmlStyle = html.style;
|
|
const bodyStyle = body.style;
|
|
const previousHtmlScrollBehavior = htmlStyle.scrollBehavior || '';
|
|
const previousBodyScrollBehavior = bodyStyle.scrollBehavior || '';
|
|
this._isEnabled = false;
|
|
htmlStyle.left = this._previousHTMLStyles.left;
|
|
htmlStyle.top = this._previousHTMLStyles.top;
|
|
html.classList.remove('cdk-global-scrollblock');
|
|
if (scrollBehaviorSupported) {
|
|
htmlStyle.scrollBehavior = bodyStyle.scrollBehavior = 'auto';
|
|
}
|
|
window.scroll(this._previousScrollPosition.left, this._previousScrollPosition.top);
|
|
if (scrollBehaviorSupported) {
|
|
htmlStyle.scrollBehavior = previousHtmlScrollBehavior;
|
|
bodyStyle.scrollBehavior = previousBodyScrollBehavior;
|
|
}
|
|
}
|
|
}
|
|
_canBeEnabled() {
|
|
const html = this._document.documentElement;
|
|
if (html.classList.contains('cdk-global-scrollblock') || this._isEnabled) {
|
|
return false;
|
|
}
|
|
const rootElement = this._document.documentElement;
|
|
const viewport = this._viewportRuler.getViewportSize();
|
|
return rootElement.scrollHeight > viewport.height || rootElement.scrollWidth > viewport.width;
|
|
}
|
|
}
|
|
|
|
function getMatScrollStrategyAlreadyAttachedError() {
|
|
return Error(`Scroll strategy has already been attached.`);
|
|
}
|
|
|
|
function createCloseScrollStrategy(injector, config) {
|
|
return new CloseScrollStrategy(injector.get(ScrollDispatcher), injector.get(NgZone), injector.get(ViewportRuler), config);
|
|
}
|
|
class CloseScrollStrategy {
|
|
_scrollDispatcher;
|
|
_ngZone;
|
|
_viewportRuler;
|
|
_config;
|
|
_scrollSubscription = null;
|
|
_overlayRef;
|
|
_initialScrollPosition;
|
|
constructor(_scrollDispatcher, _ngZone, _viewportRuler, _config) {
|
|
this._scrollDispatcher = _scrollDispatcher;
|
|
this._ngZone = _ngZone;
|
|
this._viewportRuler = _viewportRuler;
|
|
this._config = _config;
|
|
}
|
|
attach(overlayRef) {
|
|
if (this._overlayRef && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw getMatScrollStrategyAlreadyAttachedError();
|
|
}
|
|
this._overlayRef = overlayRef;
|
|
}
|
|
enable() {
|
|
if (this._scrollSubscription) {
|
|
return;
|
|
}
|
|
const stream = this._scrollDispatcher.scrolled(0).pipe(filter(scrollable => {
|
|
return !scrollable || !this._overlayRef.overlayElement.contains(scrollable.getElementRef().nativeElement);
|
|
}));
|
|
if (this._config && this._config.threshold && this._config.threshold > 1) {
|
|
this._initialScrollPosition = this._viewportRuler.getViewportScrollPosition().top;
|
|
this._scrollSubscription = stream.subscribe(() => {
|
|
const scrollPosition = this._viewportRuler.getViewportScrollPosition().top;
|
|
if (Math.abs(scrollPosition - this._initialScrollPosition) > this._config.threshold) {
|
|
this._detach();
|
|
} else {
|
|
this._overlayRef.updatePosition();
|
|
}
|
|
});
|
|
} else {
|
|
this._scrollSubscription = stream.subscribe(this._detach);
|
|
}
|
|
}
|
|
disable() {
|
|
if (this._scrollSubscription) {
|
|
this._scrollSubscription.unsubscribe();
|
|
this._scrollSubscription = null;
|
|
}
|
|
}
|
|
detach() {
|
|
this.disable();
|
|
this._overlayRef = null;
|
|
}
|
|
_detach = () => {
|
|
this.disable();
|
|
if (this._overlayRef.hasAttached()) {
|
|
this._ngZone.run(() => this._overlayRef.detach());
|
|
}
|
|
};
|
|
}
|
|
|
|
function createNoopScrollStrategy() {
|
|
return new NoopScrollStrategy();
|
|
}
|
|
class NoopScrollStrategy {
|
|
enable() {}
|
|
disable() {}
|
|
attach() {}
|
|
}
|
|
|
|
function isElementScrolledOutsideView(element, scrollContainers) {
|
|
return scrollContainers.some(containerBounds => {
|
|
const outsideAbove = element.bottom < containerBounds.top;
|
|
const outsideBelow = element.top > containerBounds.bottom;
|
|
const outsideLeft = element.right < containerBounds.left;
|
|
const outsideRight = element.left > containerBounds.right;
|
|
return outsideAbove || outsideBelow || outsideLeft || outsideRight;
|
|
});
|
|
}
|
|
function isElementClippedByScrolling(element, scrollContainers) {
|
|
return scrollContainers.some(scrollContainerRect => {
|
|
const clippedAbove = element.top < scrollContainerRect.top;
|
|
const clippedBelow = element.bottom > scrollContainerRect.bottom;
|
|
const clippedLeft = element.left < scrollContainerRect.left;
|
|
const clippedRight = element.right > scrollContainerRect.right;
|
|
return clippedAbove || clippedBelow || clippedLeft || clippedRight;
|
|
});
|
|
}
|
|
|
|
function createRepositionScrollStrategy(injector, config) {
|
|
return new RepositionScrollStrategy(injector.get(ScrollDispatcher), injector.get(ViewportRuler), injector.get(NgZone), config);
|
|
}
|
|
class RepositionScrollStrategy {
|
|
_scrollDispatcher;
|
|
_viewportRuler;
|
|
_ngZone;
|
|
_config;
|
|
_scrollSubscription = null;
|
|
_overlayRef;
|
|
constructor(_scrollDispatcher, _viewportRuler, _ngZone, _config) {
|
|
this._scrollDispatcher = _scrollDispatcher;
|
|
this._viewportRuler = _viewportRuler;
|
|
this._ngZone = _ngZone;
|
|
this._config = _config;
|
|
}
|
|
attach(overlayRef) {
|
|
if (this._overlayRef && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw getMatScrollStrategyAlreadyAttachedError();
|
|
}
|
|
this._overlayRef = overlayRef;
|
|
}
|
|
enable() {
|
|
if (!this._scrollSubscription) {
|
|
const throttle = this._config ? this._config.scrollThrottle : 0;
|
|
this._scrollSubscription = this._scrollDispatcher.scrolled(throttle).subscribe(() => {
|
|
this._overlayRef.updatePosition();
|
|
if (this._config && this._config.autoClose) {
|
|
const overlayRect = this._overlayRef.overlayElement.getBoundingClientRect();
|
|
const {
|
|
width,
|
|
height
|
|
} = this._viewportRuler.getViewportSize();
|
|
const parentRects = [{
|
|
width,
|
|
height,
|
|
bottom: height,
|
|
right: width,
|
|
top: 0,
|
|
left: 0
|
|
}];
|
|
if (isElementScrolledOutsideView(overlayRect, parentRects)) {
|
|
this.disable();
|
|
this._ngZone.run(() => this._overlayRef.detach());
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
disable() {
|
|
if (this._scrollSubscription) {
|
|
this._scrollSubscription.unsubscribe();
|
|
this._scrollSubscription = null;
|
|
}
|
|
}
|
|
detach() {
|
|
this.disable();
|
|
this._overlayRef = null;
|
|
}
|
|
}
|
|
|
|
class ScrollStrategyOptions {
|
|
_injector = inject(Injector);
|
|
constructor() {}
|
|
noop = () => new NoopScrollStrategy();
|
|
close = config => createCloseScrollStrategy(this._injector, config);
|
|
block = () => createBlockScrollStrategy(this._injector);
|
|
reposition = config => createRepositionScrollStrategy(this._injector, config);
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ScrollStrategyOptions,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Injectable
|
|
});
|
|
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ScrollStrategyOptions,
|
|
providedIn: 'root'
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ScrollStrategyOptions,
|
|
decorators: [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: 'root'
|
|
}]
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
|
|
class OverlayConfig {
|
|
positionStrategy;
|
|
scrollStrategy = new NoopScrollStrategy();
|
|
panelClass = '';
|
|
hasBackdrop = false;
|
|
backdropClass = 'cdk-overlay-dark-backdrop';
|
|
disableAnimations;
|
|
width;
|
|
height;
|
|
minWidth;
|
|
minHeight;
|
|
maxWidth;
|
|
maxHeight;
|
|
direction;
|
|
disposeOnNavigation = false;
|
|
usePopover;
|
|
constructor(config) {
|
|
if (config) {
|
|
const configKeys = Object.keys(config);
|
|
for (const key of configKeys) {
|
|
if (config[key] !== undefined) {
|
|
this[key] = config[key];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class ConnectionPositionPair {
|
|
offsetX;
|
|
offsetY;
|
|
panelClass;
|
|
originX;
|
|
originY;
|
|
overlayX;
|
|
overlayY;
|
|
constructor(origin, overlay, offsetX, offsetY, panelClass) {
|
|
this.offsetX = offsetX;
|
|
this.offsetY = offsetY;
|
|
this.panelClass = panelClass;
|
|
this.originX = origin.originX;
|
|
this.originY = origin.originY;
|
|
this.overlayX = overlay.overlayX;
|
|
this.overlayY = overlay.overlayY;
|
|
}
|
|
}
|
|
class ScrollingVisibility {
|
|
isOriginClipped = false;
|
|
isOriginOutsideView = false;
|
|
isOverlayClipped = false;
|
|
isOverlayOutsideView = false;
|
|
}
|
|
class ConnectedOverlayPositionChange {
|
|
connectionPair;
|
|
scrollableViewProperties;
|
|
constructor(connectionPair, scrollableViewProperties) {
|
|
this.connectionPair = connectionPair;
|
|
this.scrollableViewProperties = scrollableViewProperties;
|
|
}
|
|
}
|
|
function validateVerticalPosition(property, value) {
|
|
if (value !== 'top' && value !== 'bottom' && value !== 'center') {
|
|
throw Error(`ConnectedPosition: Invalid ${property} "${value}". ` + `Expected "top", "bottom" or "center".`);
|
|
}
|
|
}
|
|
function validateHorizontalPosition(property, value) {
|
|
if (value !== 'start' && value !== 'end' && value !== 'center') {
|
|
throw Error(`ConnectedPosition: Invalid ${property} "${value}". ` + `Expected "start", "end" or "center".`);
|
|
}
|
|
}
|
|
|
|
class BaseOverlayDispatcher {
|
|
_attachedOverlays = [];
|
|
_document = inject(DOCUMENT);
|
|
_isAttached = false;
|
|
constructor() {}
|
|
ngOnDestroy() {
|
|
this.detach();
|
|
}
|
|
add(overlayRef) {
|
|
this.remove(overlayRef);
|
|
this._attachedOverlays.push(overlayRef);
|
|
}
|
|
remove(overlayRef) {
|
|
const index = this._attachedOverlays.indexOf(overlayRef);
|
|
if (index > -1) {
|
|
this._attachedOverlays.splice(index, 1);
|
|
}
|
|
if (this._attachedOverlays.length === 0) {
|
|
this.detach();
|
|
}
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: BaseOverlayDispatcher,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Injectable
|
|
});
|
|
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: BaseOverlayDispatcher,
|
|
providedIn: 'root'
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: BaseOverlayDispatcher,
|
|
decorators: [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: 'root'
|
|
}]
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
|
|
class OverlayKeyboardDispatcher extends BaseOverlayDispatcher {
|
|
_ngZone = inject(NgZone);
|
|
_renderer = inject(RendererFactory2).createRenderer(null, null);
|
|
_cleanupKeydown;
|
|
add(overlayRef) {
|
|
super.add(overlayRef);
|
|
if (!this._isAttached) {
|
|
this._ngZone.runOutsideAngular(() => {
|
|
this._cleanupKeydown = this._renderer.listen('body', 'keydown', this._keydownListener);
|
|
});
|
|
this._isAttached = true;
|
|
}
|
|
}
|
|
detach() {
|
|
if (this._isAttached) {
|
|
this._cleanupKeydown?.();
|
|
this._isAttached = false;
|
|
}
|
|
}
|
|
_keydownListener = event => {
|
|
const overlays = this._attachedOverlays;
|
|
for (let i = overlays.length - 1; i > -1; i--) {
|
|
if (overlays[i]._keydownEvents.observers.length > 0) {
|
|
this._ngZone.run(() => overlays[i]._keydownEvents.next(event));
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayKeyboardDispatcher,
|
|
deps: null,
|
|
target: i0.ɵɵFactoryTarget.Injectable
|
|
});
|
|
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayKeyboardDispatcher,
|
|
providedIn: 'root'
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayKeyboardDispatcher,
|
|
decorators: [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: 'root'
|
|
}]
|
|
}]
|
|
});
|
|
|
|
class OverlayOutsideClickDispatcher extends BaseOverlayDispatcher {
|
|
_platform = inject(Platform);
|
|
_ngZone = inject(NgZone);
|
|
_renderer = inject(RendererFactory2).createRenderer(null, null);
|
|
_cursorOriginalValue;
|
|
_cursorStyleIsSet = false;
|
|
_pointerDownEventTarget = null;
|
|
_cleanups;
|
|
add(overlayRef) {
|
|
super.add(overlayRef);
|
|
if (!this._isAttached) {
|
|
const body = this._document.body;
|
|
const eventOptions = {
|
|
capture: true
|
|
};
|
|
const renderer = this._renderer;
|
|
this._cleanups = this._ngZone.runOutsideAngular(() => [renderer.listen(body, 'pointerdown', this._pointerDownListener, eventOptions), renderer.listen(body, 'click', this._clickListener, eventOptions), renderer.listen(body, 'auxclick', this._clickListener, eventOptions), renderer.listen(body, 'contextmenu', this._clickListener, eventOptions)]);
|
|
if (this._platform.IOS && !this._cursorStyleIsSet) {
|
|
this._cursorOriginalValue = body.style.cursor;
|
|
body.style.cursor = 'pointer';
|
|
this._cursorStyleIsSet = true;
|
|
}
|
|
this._isAttached = true;
|
|
}
|
|
}
|
|
detach() {
|
|
if (this._isAttached) {
|
|
this._cleanups?.forEach(cleanup => cleanup());
|
|
this._cleanups = undefined;
|
|
if (this._platform.IOS && this._cursorStyleIsSet) {
|
|
this._document.body.style.cursor = this._cursorOriginalValue;
|
|
this._cursorStyleIsSet = false;
|
|
}
|
|
this._isAttached = false;
|
|
}
|
|
}
|
|
_pointerDownListener = event => {
|
|
this._pointerDownEventTarget = _getEventTarget(event);
|
|
};
|
|
_clickListener = event => {
|
|
const target = _getEventTarget(event);
|
|
const origin = event.type === 'click' && this._pointerDownEventTarget ? this._pointerDownEventTarget : target;
|
|
this._pointerDownEventTarget = null;
|
|
const overlays = this._attachedOverlays.slice();
|
|
for (let i = overlays.length - 1; i > -1; i--) {
|
|
const overlayRef = overlays[i];
|
|
if (overlayRef._outsidePointerEvents.observers.length < 1 || !overlayRef.hasAttached()) {
|
|
continue;
|
|
}
|
|
if (containsPierceShadowDom(overlayRef.overlayElement, target) || containsPierceShadowDom(overlayRef.overlayElement, origin)) {
|
|
break;
|
|
}
|
|
const outsidePointerEvents = overlayRef._outsidePointerEvents;
|
|
if (this._ngZone) {
|
|
this._ngZone.run(() => outsidePointerEvents.next(event));
|
|
} else {
|
|
outsidePointerEvents.next(event);
|
|
}
|
|
}
|
|
};
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayOutsideClickDispatcher,
|
|
deps: null,
|
|
target: i0.ɵɵFactoryTarget.Injectable
|
|
});
|
|
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayOutsideClickDispatcher,
|
|
providedIn: 'root'
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayOutsideClickDispatcher,
|
|
decorators: [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: 'root'
|
|
}]
|
|
}]
|
|
});
|
|
function containsPierceShadowDom(parent, child) {
|
|
const supportsShadowRoot = typeof ShadowRoot !== 'undefined' && ShadowRoot;
|
|
let current = child;
|
|
while (current) {
|
|
if (current === parent) {
|
|
return true;
|
|
}
|
|
current = supportsShadowRoot && current instanceof ShadowRoot ? current.host : current.parentNode;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
class _CdkOverlayStyleLoader {
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: _CdkOverlayStyleLoader,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Component
|
|
});
|
|
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
type: _CdkOverlayStyleLoader,
|
|
isStandalone: true,
|
|
selector: "ng-component",
|
|
host: {
|
|
attributes: {
|
|
"cdk-overlay-style-loader": ""
|
|
}
|
|
},
|
|
ngImport: i0,
|
|
template: '',
|
|
isInline: true,
|
|
styles: [".cdk-overlay-container,.cdk-global-overlay-wrapper{pointer-events:none;top:0;left:0;height:100%;width:100%}.cdk-overlay-container{position:fixed}@layer cdk-overlay{.cdk-overlay-container{z-index:1000}}.cdk-overlay-container:empty{display:none}.cdk-global-overlay-wrapper{display:flex;position:absolute}@layer cdk-overlay{.cdk-global-overlay-wrapper{z-index:1000}}.cdk-overlay-pane{position:absolute;pointer-events:auto;box-sizing:border-box;display:flex;max-width:100%;max-height:100%}@layer cdk-overlay{.cdk-overlay-pane{z-index:1000}}.cdk-overlay-backdrop{position:absolute;top:0;bottom:0;left:0;right:0;pointer-events:auto;-webkit-tap-highlight-color:rgba(0,0,0,0);opacity:0;touch-action:manipulation}@layer cdk-overlay{.cdk-overlay-backdrop{z-index:1000;transition:opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}}@media(prefers-reduced-motion){.cdk-overlay-backdrop{transition-duration:1ms}}.cdk-overlay-backdrop-showing{opacity:1}@media(forced-colors: active){.cdk-overlay-backdrop-showing{opacity:.6}}@layer cdk-overlay{.cdk-overlay-dark-backdrop{background:rgba(0,0,0,.32)}}.cdk-overlay-transparent-backdrop{transition:visibility 1ms linear,opacity 1ms linear;visibility:hidden;opacity:1}.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing,.cdk-high-contrast-active .cdk-overlay-transparent-backdrop{opacity:0;visibility:visible}.cdk-overlay-backdrop-noop-animation{transition:none}.cdk-overlay-connected-position-bounding-box{position:absolute;display:flex;flex-direction:column;min-width:1px;min-height:1px}@layer cdk-overlay{.cdk-overlay-connected-position-bounding-box{z-index:1000}}.cdk-global-scrollblock{position:fixed;width:100%;overflow-y:scroll}.cdk-overlay-popover{background:none;border:none;padding:0;outline:0;overflow:visible;position:fixed;pointer-events:none;white-space:normal;color:inherit;text-decoration:none;width:100%;height:100%;inset:auto;top:0;left:0}.cdk-overlay-popover::backdrop{display:none}.cdk-overlay-popover .cdk-overlay-backdrop{position:fixed;z-index:auto}\n"],
|
|
changeDetection: i0.ChangeDetectionStrategy.OnPush,
|
|
encapsulation: i0.ViewEncapsulation.None
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: _CdkOverlayStyleLoader,
|
|
decorators: [{
|
|
type: Component,
|
|
args: [{
|
|
template: '',
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
encapsulation: ViewEncapsulation.None,
|
|
host: {
|
|
'cdk-overlay-style-loader': ''
|
|
},
|
|
styles: [".cdk-overlay-container,.cdk-global-overlay-wrapper{pointer-events:none;top:0;left:0;height:100%;width:100%}.cdk-overlay-container{position:fixed}@layer cdk-overlay{.cdk-overlay-container{z-index:1000}}.cdk-overlay-container:empty{display:none}.cdk-global-overlay-wrapper{display:flex;position:absolute}@layer cdk-overlay{.cdk-global-overlay-wrapper{z-index:1000}}.cdk-overlay-pane{position:absolute;pointer-events:auto;box-sizing:border-box;display:flex;max-width:100%;max-height:100%}@layer cdk-overlay{.cdk-overlay-pane{z-index:1000}}.cdk-overlay-backdrop{position:absolute;top:0;bottom:0;left:0;right:0;pointer-events:auto;-webkit-tap-highlight-color:rgba(0,0,0,0);opacity:0;touch-action:manipulation}@layer cdk-overlay{.cdk-overlay-backdrop{z-index:1000;transition:opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1)}}@media(prefers-reduced-motion){.cdk-overlay-backdrop{transition-duration:1ms}}.cdk-overlay-backdrop-showing{opacity:1}@media(forced-colors: active){.cdk-overlay-backdrop-showing{opacity:.6}}@layer cdk-overlay{.cdk-overlay-dark-backdrop{background:rgba(0,0,0,.32)}}.cdk-overlay-transparent-backdrop{transition:visibility 1ms linear,opacity 1ms linear;visibility:hidden;opacity:1}.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing,.cdk-high-contrast-active .cdk-overlay-transparent-backdrop{opacity:0;visibility:visible}.cdk-overlay-backdrop-noop-animation{transition:none}.cdk-overlay-connected-position-bounding-box{position:absolute;display:flex;flex-direction:column;min-width:1px;min-height:1px}@layer cdk-overlay{.cdk-overlay-connected-position-bounding-box{z-index:1000}}.cdk-global-scrollblock{position:fixed;width:100%;overflow-y:scroll}.cdk-overlay-popover{background:none;border:none;padding:0;outline:0;overflow:visible;position:fixed;pointer-events:none;white-space:normal;color:inherit;text-decoration:none;width:100%;height:100%;inset:auto;top:0;left:0}.cdk-overlay-popover::backdrop{display:none}.cdk-overlay-popover .cdk-overlay-backdrop{position:fixed;z-index:auto}\n"]
|
|
}]
|
|
}]
|
|
});
|
|
class OverlayContainer {
|
|
_platform = inject(Platform);
|
|
_containerElement;
|
|
_document = inject(DOCUMENT);
|
|
_styleLoader = inject(_CdkPrivateStyleLoader);
|
|
constructor() {}
|
|
ngOnDestroy() {
|
|
this._containerElement?.remove();
|
|
}
|
|
getContainerElement() {
|
|
this._loadStyles();
|
|
if (!this._containerElement) {
|
|
this._createContainer();
|
|
}
|
|
return this._containerElement;
|
|
}
|
|
_createContainer() {
|
|
const containerClass = 'cdk-overlay-container';
|
|
if (this._platform.isBrowser || _isTestEnvironment()) {
|
|
const oppositePlatformContainers = this._document.querySelectorAll(`.${containerClass}[platform="server"], ` + `.${containerClass}[platform="test"]`);
|
|
for (let i = 0; i < oppositePlatformContainers.length; i++) {
|
|
oppositePlatformContainers[i].remove();
|
|
}
|
|
}
|
|
const container = this._document.createElement('div');
|
|
container.classList.add(containerClass);
|
|
if (_isTestEnvironment()) {
|
|
container.setAttribute('platform', 'test');
|
|
} else if (!this._platform.isBrowser) {
|
|
container.setAttribute('platform', 'server');
|
|
}
|
|
this._document.body.appendChild(container);
|
|
this._containerElement = container;
|
|
}
|
|
_loadStyles() {
|
|
this._styleLoader.load(_CdkOverlayStyleLoader);
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayContainer,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Injectable
|
|
});
|
|
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayContainer,
|
|
providedIn: 'root'
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayContainer,
|
|
decorators: [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: 'root'
|
|
}]
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
|
|
class BackdropRef {
|
|
_renderer;
|
|
_ngZone;
|
|
element;
|
|
_cleanupClick;
|
|
_cleanupTransitionEnd;
|
|
_fallbackTimeout;
|
|
constructor(document, _renderer, _ngZone, onClick) {
|
|
this._renderer = _renderer;
|
|
this._ngZone = _ngZone;
|
|
this.element = document.createElement('div');
|
|
this.element.classList.add('cdk-overlay-backdrop');
|
|
this._cleanupClick = _renderer.listen(this.element, 'click', onClick);
|
|
}
|
|
detach() {
|
|
this._ngZone.runOutsideAngular(() => {
|
|
const element = this.element;
|
|
clearTimeout(this._fallbackTimeout);
|
|
this._cleanupTransitionEnd?.();
|
|
this._cleanupTransitionEnd = this._renderer.listen(element, 'transitionend', this.dispose);
|
|
this._fallbackTimeout = setTimeout(this.dispose, 500);
|
|
element.style.pointerEvents = 'none';
|
|
element.classList.remove('cdk-overlay-backdrop-showing');
|
|
});
|
|
}
|
|
dispose = () => {
|
|
clearTimeout(this._fallbackTimeout);
|
|
this._cleanupClick?.();
|
|
this._cleanupTransitionEnd?.();
|
|
this._cleanupClick = this._cleanupTransitionEnd = this._fallbackTimeout = undefined;
|
|
this.element.remove();
|
|
};
|
|
}
|
|
|
|
function isElement(value) {
|
|
return value && value.nodeType === 1;
|
|
}
|
|
class OverlayRef {
|
|
_portalOutlet;
|
|
_host;
|
|
_pane;
|
|
_config;
|
|
_ngZone;
|
|
_keyboardDispatcher;
|
|
_document;
|
|
_location;
|
|
_outsideClickDispatcher;
|
|
_animationsDisabled;
|
|
_injector;
|
|
_renderer;
|
|
_backdropClick = new Subject();
|
|
_attachments = new Subject();
|
|
_detachments = new Subject();
|
|
_positionStrategy;
|
|
_scrollStrategy;
|
|
_locationChanges = Subscription.EMPTY;
|
|
_backdropRef = null;
|
|
_detachContentMutationObserver;
|
|
_detachContentAfterRenderRef;
|
|
_disposed = false;
|
|
_previousHostParent;
|
|
_keydownEvents = new Subject();
|
|
_outsidePointerEvents = new Subject();
|
|
_afterNextRenderRef;
|
|
constructor(_portalOutlet, _host, _pane, _config, _ngZone, _keyboardDispatcher, _document, _location, _outsideClickDispatcher, _animationsDisabled = false, _injector, _renderer) {
|
|
this._portalOutlet = _portalOutlet;
|
|
this._host = _host;
|
|
this._pane = _pane;
|
|
this._config = _config;
|
|
this._ngZone = _ngZone;
|
|
this._keyboardDispatcher = _keyboardDispatcher;
|
|
this._document = _document;
|
|
this._location = _location;
|
|
this._outsideClickDispatcher = _outsideClickDispatcher;
|
|
this._animationsDisabled = _animationsDisabled;
|
|
this._injector = _injector;
|
|
this._renderer = _renderer;
|
|
if (_config.scrollStrategy) {
|
|
this._scrollStrategy = _config.scrollStrategy;
|
|
this._scrollStrategy.attach(this);
|
|
}
|
|
this._positionStrategy = _config.positionStrategy;
|
|
}
|
|
get overlayElement() {
|
|
return this._pane;
|
|
}
|
|
get backdropElement() {
|
|
return this._backdropRef?.element || null;
|
|
}
|
|
get hostElement() {
|
|
return this._host;
|
|
}
|
|
attach(portal) {
|
|
if (this._disposed) {
|
|
return null;
|
|
}
|
|
this._attachHost();
|
|
const attachResult = this._portalOutlet.attach(portal);
|
|
this._positionStrategy?.attach(this);
|
|
this._updateStackingOrder();
|
|
this._updateElementSize();
|
|
this._updateElementDirection();
|
|
if (this._scrollStrategy) {
|
|
this._scrollStrategy.enable();
|
|
}
|
|
this._afterNextRenderRef?.destroy();
|
|
this._afterNextRenderRef = afterNextRender(() => {
|
|
if (this.hasAttached()) {
|
|
this.updatePosition();
|
|
}
|
|
}, {
|
|
injector: this._injector
|
|
});
|
|
this._togglePointerEvents(true);
|
|
if (this._config.hasBackdrop) {
|
|
this._attachBackdrop();
|
|
}
|
|
if (this._config.panelClass) {
|
|
this._toggleClasses(this._pane, this._config.panelClass, true);
|
|
}
|
|
this._attachments.next();
|
|
this._completeDetachContent();
|
|
this._keyboardDispatcher.add(this);
|
|
if (this._config.disposeOnNavigation) {
|
|
this._locationChanges = this._location.subscribe(() => this.dispose());
|
|
}
|
|
this._outsideClickDispatcher.add(this);
|
|
if (typeof attachResult?.onDestroy === 'function') {
|
|
attachResult.onDestroy(() => {
|
|
if (this.hasAttached()) {
|
|
this._ngZone.runOutsideAngular(() => Promise.resolve().then(() => this.detach()));
|
|
}
|
|
});
|
|
}
|
|
return attachResult;
|
|
}
|
|
detach() {
|
|
if (!this.hasAttached()) {
|
|
return;
|
|
}
|
|
this.detachBackdrop();
|
|
this._togglePointerEvents(false);
|
|
if (this._positionStrategy && this._positionStrategy.detach) {
|
|
this._positionStrategy.detach();
|
|
}
|
|
if (this._scrollStrategy) {
|
|
this._scrollStrategy.disable();
|
|
}
|
|
const detachmentResult = this._portalOutlet.detach();
|
|
this._detachments.next();
|
|
this._completeDetachContent();
|
|
this._keyboardDispatcher.remove(this);
|
|
this._detachContentWhenEmpty();
|
|
this._locationChanges.unsubscribe();
|
|
this._outsideClickDispatcher.remove(this);
|
|
return detachmentResult;
|
|
}
|
|
dispose() {
|
|
if (this._disposed) {
|
|
return;
|
|
}
|
|
const isAttached = this.hasAttached();
|
|
if (this._positionStrategy) {
|
|
this._positionStrategy.dispose();
|
|
}
|
|
this._disposeScrollStrategy();
|
|
this._backdropRef?.dispose();
|
|
this._locationChanges.unsubscribe();
|
|
this._keyboardDispatcher.remove(this);
|
|
this._portalOutlet.dispose();
|
|
this._attachments.complete();
|
|
this._backdropClick.complete();
|
|
this._keydownEvents.complete();
|
|
this._outsidePointerEvents.complete();
|
|
this._outsideClickDispatcher.remove(this);
|
|
this._host?.remove();
|
|
this._afterNextRenderRef?.destroy();
|
|
this._previousHostParent = this._pane = this._host = this._backdropRef = null;
|
|
if (isAttached) {
|
|
this._detachments.next();
|
|
}
|
|
this._detachments.complete();
|
|
this._completeDetachContent();
|
|
this._disposed = true;
|
|
}
|
|
hasAttached() {
|
|
return this._portalOutlet.hasAttached();
|
|
}
|
|
backdropClick() {
|
|
return this._backdropClick;
|
|
}
|
|
attachments() {
|
|
return this._attachments;
|
|
}
|
|
detachments() {
|
|
return this._detachments;
|
|
}
|
|
keydownEvents() {
|
|
return this._keydownEvents;
|
|
}
|
|
outsidePointerEvents() {
|
|
return this._outsidePointerEvents;
|
|
}
|
|
getConfig() {
|
|
return this._config;
|
|
}
|
|
updatePosition() {
|
|
if (this._positionStrategy) {
|
|
this._positionStrategy.apply();
|
|
}
|
|
}
|
|
updatePositionStrategy(strategy) {
|
|
if (strategy === this._positionStrategy) {
|
|
return;
|
|
}
|
|
if (this._positionStrategy) {
|
|
this._positionStrategy.dispose();
|
|
}
|
|
this._positionStrategy = strategy;
|
|
if (this.hasAttached()) {
|
|
strategy.attach(this);
|
|
this.updatePosition();
|
|
}
|
|
}
|
|
updateSize(sizeConfig) {
|
|
this._config = {
|
|
...this._config,
|
|
...sizeConfig
|
|
};
|
|
this._updateElementSize();
|
|
}
|
|
setDirection(dir) {
|
|
this._config = {
|
|
...this._config,
|
|
direction: dir
|
|
};
|
|
this._updateElementDirection();
|
|
}
|
|
addPanelClass(classes) {
|
|
if (this._pane) {
|
|
this._toggleClasses(this._pane, classes, true);
|
|
}
|
|
}
|
|
removePanelClass(classes) {
|
|
if (this._pane) {
|
|
this._toggleClasses(this._pane, classes, false);
|
|
}
|
|
}
|
|
getDirection() {
|
|
const direction = this._config.direction;
|
|
if (!direction) {
|
|
return 'ltr';
|
|
}
|
|
return typeof direction === 'string' ? direction : direction.value;
|
|
}
|
|
updateScrollStrategy(strategy) {
|
|
if (strategy === this._scrollStrategy) {
|
|
return;
|
|
}
|
|
this._disposeScrollStrategy();
|
|
this._scrollStrategy = strategy;
|
|
if (this.hasAttached()) {
|
|
strategy.attach(this);
|
|
strategy.enable();
|
|
}
|
|
}
|
|
_updateElementDirection() {
|
|
this._host.setAttribute('dir', this.getDirection());
|
|
}
|
|
_updateElementSize() {
|
|
if (!this._pane) {
|
|
return;
|
|
}
|
|
const style = this._pane.style;
|
|
style.width = coerceCssPixelValue(this._config.width);
|
|
style.height = coerceCssPixelValue(this._config.height);
|
|
style.minWidth = coerceCssPixelValue(this._config.minWidth);
|
|
style.minHeight = coerceCssPixelValue(this._config.minHeight);
|
|
style.maxWidth = coerceCssPixelValue(this._config.maxWidth);
|
|
style.maxHeight = coerceCssPixelValue(this._config.maxHeight);
|
|
}
|
|
_togglePointerEvents(enablePointer) {
|
|
this._pane.style.pointerEvents = enablePointer ? '' : 'none';
|
|
}
|
|
_attachHost() {
|
|
if (!this._host.parentElement) {
|
|
const customInsertionPoint = this._config.usePopover ? this._positionStrategy?.getPopoverInsertionPoint?.() : null;
|
|
if (isElement(customInsertionPoint)) {
|
|
customInsertionPoint.after(this._host);
|
|
} else if (customInsertionPoint?.type === 'parent') {
|
|
customInsertionPoint.element.appendChild(this._host);
|
|
} else {
|
|
this._previousHostParent?.appendChild(this._host);
|
|
}
|
|
}
|
|
if (this._config.usePopover) {
|
|
try {
|
|
this._host['showPopover']();
|
|
} catch {}
|
|
}
|
|
}
|
|
_attachBackdrop() {
|
|
const showingClass = 'cdk-overlay-backdrop-showing';
|
|
this._backdropRef?.dispose();
|
|
this._backdropRef = new BackdropRef(this._document, this._renderer, this._ngZone, event => {
|
|
this._backdropClick.next(event);
|
|
});
|
|
if (this._animationsDisabled) {
|
|
this._backdropRef.element.classList.add('cdk-overlay-backdrop-noop-animation');
|
|
}
|
|
if (this._config.backdropClass) {
|
|
this._toggleClasses(this._backdropRef.element, this._config.backdropClass, true);
|
|
}
|
|
if (this._config.usePopover) {
|
|
this._host.prepend(this._backdropRef.element);
|
|
} else {
|
|
this._host.parentElement.insertBefore(this._backdropRef.element, this._host);
|
|
}
|
|
if (!this._animationsDisabled && typeof requestAnimationFrame !== 'undefined') {
|
|
this._ngZone.runOutsideAngular(() => {
|
|
requestAnimationFrame(() => this._backdropRef?.element.classList.add(showingClass));
|
|
});
|
|
} else {
|
|
this._backdropRef.element.classList.add(showingClass);
|
|
}
|
|
}
|
|
_updateStackingOrder() {
|
|
if (!this._config.usePopover && this._host.nextSibling) {
|
|
this._host.parentNode.appendChild(this._host);
|
|
}
|
|
}
|
|
detachBackdrop() {
|
|
if (this._animationsDisabled) {
|
|
this._backdropRef?.dispose();
|
|
this._backdropRef = null;
|
|
} else {
|
|
this._backdropRef?.detach();
|
|
}
|
|
}
|
|
_toggleClasses(element, cssClasses, isAdd) {
|
|
const classes = coerceArray(cssClasses || []).filter(c => !!c);
|
|
if (classes.length) {
|
|
isAdd ? element.classList.add(...classes) : element.classList.remove(...classes);
|
|
}
|
|
}
|
|
_detachContentWhenEmpty() {
|
|
let rethrow = false;
|
|
try {
|
|
this._detachContentAfterRenderRef = afterNextRender(() => {
|
|
rethrow = true;
|
|
this._detachContent();
|
|
}, {
|
|
injector: this._injector
|
|
});
|
|
} catch (e) {
|
|
if (rethrow) {
|
|
throw e;
|
|
}
|
|
this._detachContent();
|
|
}
|
|
if (globalThis.MutationObserver && this._pane) {
|
|
this._detachContentMutationObserver ||= new globalThis.MutationObserver(() => {
|
|
this._detachContent();
|
|
});
|
|
this._detachContentMutationObserver.observe(this._pane, {
|
|
childList: true
|
|
});
|
|
}
|
|
}
|
|
_detachContent() {
|
|
if (!this._pane || !this._host || this._pane.children.length === 0) {
|
|
if (this._pane && this._config.panelClass) {
|
|
this._toggleClasses(this._pane, this._config.panelClass, false);
|
|
}
|
|
if (this._host && this._host.parentElement) {
|
|
this._previousHostParent = this._host.parentElement;
|
|
this._host.remove();
|
|
}
|
|
this._completeDetachContent();
|
|
}
|
|
}
|
|
_completeDetachContent() {
|
|
this._detachContentAfterRenderRef?.destroy();
|
|
this._detachContentAfterRenderRef = undefined;
|
|
this._detachContentMutationObserver?.disconnect();
|
|
}
|
|
_disposeScrollStrategy() {
|
|
const scrollStrategy = this._scrollStrategy;
|
|
scrollStrategy?.disable();
|
|
scrollStrategy?.detach?.();
|
|
}
|
|
}
|
|
|
|
const boundingBoxClass = 'cdk-overlay-connected-position-bounding-box';
|
|
const cssUnitPattern = /([A-Za-z%]+)$/;
|
|
function createFlexibleConnectedPositionStrategy(injector, origin) {
|
|
return new FlexibleConnectedPositionStrategy(origin, injector.get(ViewportRuler), injector.get(DOCUMENT), injector.get(Platform), injector.get(OverlayContainer));
|
|
}
|
|
class FlexibleConnectedPositionStrategy {
|
|
_viewportRuler;
|
|
_document;
|
|
_platform;
|
|
_overlayContainer;
|
|
_overlayRef;
|
|
_isInitialRender = false;
|
|
_lastBoundingBoxSize = {
|
|
width: 0,
|
|
height: 0
|
|
};
|
|
_isPushed = false;
|
|
_canPush = true;
|
|
_growAfterOpen = false;
|
|
_hasFlexibleDimensions = true;
|
|
_positionLocked = false;
|
|
_originRect;
|
|
_overlayRect;
|
|
_viewportRect;
|
|
_containerRect;
|
|
_viewportMargin = 0;
|
|
_scrollables = [];
|
|
_preferredPositions = [];
|
|
_origin;
|
|
_pane;
|
|
_isDisposed = false;
|
|
_boundingBox = null;
|
|
_lastPosition = null;
|
|
_lastScrollVisibility = null;
|
|
_positionChanges = new Subject();
|
|
_resizeSubscription = Subscription.EMPTY;
|
|
_offsetX = 0;
|
|
_offsetY = 0;
|
|
_transformOriginSelector;
|
|
_appliedPanelClasses = [];
|
|
_previousPushAmount = null;
|
|
_popoverLocation = 'global';
|
|
positionChanges = this._positionChanges;
|
|
get positions() {
|
|
return this._preferredPositions;
|
|
}
|
|
constructor(connectedTo, _viewportRuler, _document, _platform, _overlayContainer) {
|
|
this._viewportRuler = _viewportRuler;
|
|
this._document = _document;
|
|
this._platform = _platform;
|
|
this._overlayContainer = _overlayContainer;
|
|
this.setOrigin(connectedTo);
|
|
}
|
|
attach(overlayRef) {
|
|
if (this._overlayRef && overlayRef !== this._overlayRef && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw Error('This position strategy is already attached to an overlay');
|
|
}
|
|
this._validatePositions();
|
|
overlayRef.hostElement.classList.add(boundingBoxClass);
|
|
this._overlayRef = overlayRef;
|
|
this._boundingBox = overlayRef.hostElement;
|
|
this._pane = overlayRef.overlayElement;
|
|
this._isDisposed = false;
|
|
this._isInitialRender = true;
|
|
this._lastPosition = null;
|
|
this._resizeSubscription.unsubscribe();
|
|
this._resizeSubscription = this._viewportRuler.change().subscribe(() => {
|
|
this._isInitialRender = true;
|
|
this.apply();
|
|
});
|
|
}
|
|
apply() {
|
|
if (this._isDisposed || !this._platform.isBrowser) {
|
|
return;
|
|
}
|
|
if (!this._isInitialRender && this._positionLocked && this._lastPosition) {
|
|
this.reapplyLastPosition();
|
|
return;
|
|
}
|
|
this._clearPanelClasses();
|
|
this._resetOverlayElementStyles();
|
|
this._resetBoundingBoxStyles();
|
|
this._viewportRect = this._getNarrowedViewportRect();
|
|
this._originRect = this._getOriginRect();
|
|
this._overlayRect = this._pane.getBoundingClientRect();
|
|
this._containerRect = this._getContainerRect();
|
|
const originRect = this._originRect;
|
|
const overlayRect = this._overlayRect;
|
|
const viewportRect = this._viewportRect;
|
|
const containerRect = this._containerRect;
|
|
const flexibleFits = [];
|
|
let fallback;
|
|
for (let pos of this._preferredPositions) {
|
|
let originPoint = this._getOriginPoint(originRect, containerRect, pos);
|
|
let overlayPoint = this._getOverlayPoint(originPoint, overlayRect, pos);
|
|
let overlayFit = this._getOverlayFit(overlayPoint, overlayRect, viewportRect, pos);
|
|
if (overlayFit.isCompletelyWithinViewport) {
|
|
this._isPushed = false;
|
|
this._applyPosition(pos, originPoint);
|
|
return;
|
|
}
|
|
if (this._canFitWithFlexibleDimensions(overlayFit, overlayPoint, viewportRect)) {
|
|
flexibleFits.push({
|
|
position: pos,
|
|
origin: originPoint,
|
|
overlayRect,
|
|
boundingBoxRect: this._calculateBoundingBoxRect(originPoint, pos)
|
|
});
|
|
continue;
|
|
}
|
|
if (!fallback || fallback.overlayFit.visibleArea < overlayFit.visibleArea) {
|
|
fallback = {
|
|
overlayFit,
|
|
overlayPoint,
|
|
originPoint,
|
|
position: pos,
|
|
overlayRect
|
|
};
|
|
}
|
|
}
|
|
if (flexibleFits.length) {
|
|
let bestFit = null;
|
|
let bestScore = -1;
|
|
for (const fit of flexibleFits) {
|
|
const score = fit.boundingBoxRect.width * fit.boundingBoxRect.height * (fit.position.weight || 1);
|
|
if (score > bestScore) {
|
|
bestScore = score;
|
|
bestFit = fit;
|
|
}
|
|
}
|
|
this._isPushed = false;
|
|
this._applyPosition(bestFit.position, bestFit.origin);
|
|
return;
|
|
}
|
|
if (this._canPush) {
|
|
this._isPushed = true;
|
|
this._applyPosition(fallback.position, fallback.originPoint);
|
|
return;
|
|
}
|
|
this._applyPosition(fallback.position, fallback.originPoint);
|
|
}
|
|
detach() {
|
|
this._clearPanelClasses();
|
|
this._lastPosition = null;
|
|
this._previousPushAmount = null;
|
|
this._resizeSubscription.unsubscribe();
|
|
}
|
|
dispose() {
|
|
if (this._isDisposed) {
|
|
return;
|
|
}
|
|
if (this._boundingBox) {
|
|
extendStyles(this._boundingBox.style, {
|
|
top: '',
|
|
left: '',
|
|
right: '',
|
|
bottom: '',
|
|
height: '',
|
|
width: '',
|
|
alignItems: '',
|
|
justifyContent: ''
|
|
});
|
|
}
|
|
if (this._pane) {
|
|
this._resetOverlayElementStyles();
|
|
}
|
|
if (this._overlayRef) {
|
|
this._overlayRef.hostElement.classList.remove(boundingBoxClass);
|
|
}
|
|
this.detach();
|
|
this._positionChanges.complete();
|
|
this._overlayRef = this._boundingBox = null;
|
|
this._isDisposed = true;
|
|
}
|
|
reapplyLastPosition() {
|
|
if (this._isDisposed || !this._platform.isBrowser) {
|
|
return;
|
|
}
|
|
const lastPosition = this._lastPosition;
|
|
if (lastPosition) {
|
|
this._originRect = this._getOriginRect();
|
|
this._overlayRect = this._pane.getBoundingClientRect();
|
|
this._viewportRect = this._getNarrowedViewportRect();
|
|
this._containerRect = this._getContainerRect();
|
|
this._applyPosition(lastPosition, this._getOriginPoint(this._originRect, this._containerRect, lastPosition));
|
|
} else {
|
|
this.apply();
|
|
}
|
|
}
|
|
withScrollableContainers(scrollables) {
|
|
this._scrollables = scrollables;
|
|
return this;
|
|
}
|
|
withPositions(positions) {
|
|
this._preferredPositions = positions;
|
|
if (positions.indexOf(this._lastPosition) === -1) {
|
|
this._lastPosition = null;
|
|
}
|
|
this._validatePositions();
|
|
return this;
|
|
}
|
|
withViewportMargin(margin) {
|
|
this._viewportMargin = margin;
|
|
return this;
|
|
}
|
|
withFlexibleDimensions(flexibleDimensions = true) {
|
|
this._hasFlexibleDimensions = flexibleDimensions;
|
|
return this;
|
|
}
|
|
withGrowAfterOpen(growAfterOpen = true) {
|
|
this._growAfterOpen = growAfterOpen;
|
|
return this;
|
|
}
|
|
withPush(canPush = true) {
|
|
this._canPush = canPush;
|
|
return this;
|
|
}
|
|
withLockedPosition(isLocked = true) {
|
|
this._positionLocked = isLocked;
|
|
return this;
|
|
}
|
|
setOrigin(origin) {
|
|
this._origin = origin;
|
|
return this;
|
|
}
|
|
withDefaultOffsetX(offset) {
|
|
this._offsetX = offset;
|
|
return this;
|
|
}
|
|
withDefaultOffsetY(offset) {
|
|
this._offsetY = offset;
|
|
return this;
|
|
}
|
|
withTransformOriginOn(selector) {
|
|
this._transformOriginSelector = selector;
|
|
return this;
|
|
}
|
|
withPopoverLocation(location) {
|
|
this._popoverLocation = location;
|
|
return this;
|
|
}
|
|
getPopoverInsertionPoint() {
|
|
if (this._popoverLocation === 'global') {
|
|
return null;
|
|
} else if (this._popoverLocation !== 'inline') {
|
|
return this._popoverLocation;
|
|
}
|
|
if (this._origin instanceof ElementRef) {
|
|
return this._origin.nativeElement;
|
|
} else if (isElement(this._origin)) {
|
|
return this._origin;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
_getOriginPoint(originRect, containerRect, pos) {
|
|
let x;
|
|
if (pos.originX == 'center') {
|
|
x = originRect.left + originRect.width / 2;
|
|
} else {
|
|
const startX = this._isRtl() ? originRect.right : originRect.left;
|
|
const endX = this._isRtl() ? originRect.left : originRect.right;
|
|
x = pos.originX == 'start' ? startX : endX;
|
|
}
|
|
if (containerRect.left < 0) {
|
|
x -= containerRect.left;
|
|
}
|
|
let y;
|
|
if (pos.originY == 'center') {
|
|
y = originRect.top + originRect.height / 2;
|
|
} else {
|
|
y = pos.originY == 'top' ? originRect.top : originRect.bottom;
|
|
}
|
|
if (containerRect.top < 0) {
|
|
y -= containerRect.top;
|
|
}
|
|
return {
|
|
x,
|
|
y
|
|
};
|
|
}
|
|
_getOverlayPoint(originPoint, overlayRect, pos) {
|
|
let overlayStartX;
|
|
if (pos.overlayX == 'center') {
|
|
overlayStartX = -overlayRect.width / 2;
|
|
} else if (pos.overlayX === 'start') {
|
|
overlayStartX = this._isRtl() ? -overlayRect.width : 0;
|
|
} else {
|
|
overlayStartX = this._isRtl() ? 0 : -overlayRect.width;
|
|
}
|
|
let overlayStartY;
|
|
if (pos.overlayY == 'center') {
|
|
overlayStartY = -overlayRect.height / 2;
|
|
} else {
|
|
overlayStartY = pos.overlayY == 'top' ? 0 : -overlayRect.height;
|
|
}
|
|
return {
|
|
x: originPoint.x + overlayStartX,
|
|
y: originPoint.y + overlayStartY
|
|
};
|
|
}
|
|
_getOverlayFit(point, rawOverlayRect, viewport, position) {
|
|
const overlay = getRoundedBoundingClientRect(rawOverlayRect);
|
|
let {
|
|
x,
|
|
y
|
|
} = point;
|
|
let offsetX = this._getOffset(position, 'x');
|
|
let offsetY = this._getOffset(position, 'y');
|
|
if (offsetX) {
|
|
x += offsetX;
|
|
}
|
|
if (offsetY) {
|
|
y += offsetY;
|
|
}
|
|
let leftOverflow = 0 - x;
|
|
let rightOverflow = x + overlay.width - viewport.width;
|
|
let topOverflow = 0 - y;
|
|
let bottomOverflow = y + overlay.height - viewport.height;
|
|
let visibleWidth = this._subtractOverflows(overlay.width, leftOverflow, rightOverflow);
|
|
let visibleHeight = this._subtractOverflows(overlay.height, topOverflow, bottomOverflow);
|
|
let visibleArea = visibleWidth * visibleHeight;
|
|
return {
|
|
visibleArea,
|
|
isCompletelyWithinViewport: overlay.width * overlay.height === visibleArea,
|
|
fitsInViewportVertically: visibleHeight === overlay.height,
|
|
fitsInViewportHorizontally: visibleWidth == overlay.width
|
|
};
|
|
}
|
|
_canFitWithFlexibleDimensions(fit, point, viewport) {
|
|
if (this._hasFlexibleDimensions) {
|
|
const availableHeight = viewport.bottom - point.y;
|
|
const availableWidth = viewport.right - point.x;
|
|
const minHeight = getPixelValue(this._overlayRef.getConfig().minHeight);
|
|
const minWidth = getPixelValue(this._overlayRef.getConfig().minWidth);
|
|
const verticalFit = fit.fitsInViewportVertically || minHeight != null && minHeight <= availableHeight;
|
|
const horizontalFit = fit.fitsInViewportHorizontally || minWidth != null && minWidth <= availableWidth;
|
|
return verticalFit && horizontalFit;
|
|
}
|
|
return false;
|
|
}
|
|
_pushOverlayOnScreen(start, rawOverlayRect, scrollPosition) {
|
|
if (this._previousPushAmount && this._positionLocked) {
|
|
return {
|
|
x: start.x + this._previousPushAmount.x,
|
|
y: start.y + this._previousPushAmount.y
|
|
};
|
|
}
|
|
const overlay = getRoundedBoundingClientRect(rawOverlayRect);
|
|
const viewport = this._viewportRect;
|
|
const overflowRight = Math.max(start.x + overlay.width - viewport.width, 0);
|
|
const overflowBottom = Math.max(start.y + overlay.height - viewport.height, 0);
|
|
const overflowTop = Math.max(viewport.top - scrollPosition.top - start.y, 0);
|
|
const overflowLeft = Math.max(viewport.left - scrollPosition.left - start.x, 0);
|
|
let pushX = 0;
|
|
let pushY = 0;
|
|
if (overlay.width <= viewport.width) {
|
|
pushX = overflowLeft || -overflowRight;
|
|
} else {
|
|
pushX = start.x < this._getViewportMarginStart() ? viewport.left - scrollPosition.left - start.x : 0;
|
|
}
|
|
if (overlay.height <= viewport.height) {
|
|
pushY = overflowTop || -overflowBottom;
|
|
} else {
|
|
pushY = start.y < this._getViewportMarginTop() ? viewport.top - scrollPosition.top - start.y : 0;
|
|
}
|
|
this._previousPushAmount = {
|
|
x: pushX,
|
|
y: pushY
|
|
};
|
|
return {
|
|
x: start.x + pushX,
|
|
y: start.y + pushY
|
|
};
|
|
}
|
|
_applyPosition(position, originPoint) {
|
|
this._setTransformOrigin(position);
|
|
this._setOverlayElementStyles(originPoint, position);
|
|
this._setBoundingBoxStyles(originPoint, position);
|
|
if (position.panelClass) {
|
|
this._addPanelClasses(position.panelClass);
|
|
}
|
|
if (this._positionChanges.observers.length) {
|
|
const scrollVisibility = this._getScrollVisibility();
|
|
if (position !== this._lastPosition || !this._lastScrollVisibility || !compareScrollVisibility(this._lastScrollVisibility, scrollVisibility)) {
|
|
const changeEvent = new ConnectedOverlayPositionChange(position, scrollVisibility);
|
|
this._positionChanges.next(changeEvent);
|
|
}
|
|
this._lastScrollVisibility = scrollVisibility;
|
|
}
|
|
this._lastPosition = position;
|
|
this._isInitialRender = false;
|
|
}
|
|
_setTransformOrigin(position) {
|
|
if (!this._transformOriginSelector) {
|
|
return;
|
|
}
|
|
const elements = this._boundingBox.querySelectorAll(this._transformOriginSelector);
|
|
let xOrigin;
|
|
let yOrigin = position.overlayY;
|
|
if (position.overlayX === 'center') {
|
|
xOrigin = 'center';
|
|
} else if (this._isRtl()) {
|
|
xOrigin = position.overlayX === 'start' ? 'right' : 'left';
|
|
} else {
|
|
xOrigin = position.overlayX === 'start' ? 'left' : 'right';
|
|
}
|
|
for (let i = 0; i < elements.length; i++) {
|
|
elements[i].style.transformOrigin = `${xOrigin} ${yOrigin}`;
|
|
}
|
|
}
|
|
_calculateBoundingBoxRect(origin, position) {
|
|
const viewport = this._viewportRect;
|
|
const isRtl = this._isRtl();
|
|
let height, top, bottom;
|
|
if (position.overlayY === 'top') {
|
|
top = origin.y;
|
|
height = viewport.height - top + this._getViewportMarginBottom();
|
|
} else if (position.overlayY === 'bottom') {
|
|
bottom = viewport.height - origin.y + this._getViewportMarginTop() + this._getViewportMarginBottom();
|
|
height = viewport.height - bottom + this._getViewportMarginTop();
|
|
} else {
|
|
const smallestDistanceToViewportEdge = Math.min(viewport.bottom - origin.y + viewport.top, origin.y);
|
|
const previousHeight = this._lastBoundingBoxSize.height;
|
|
height = smallestDistanceToViewportEdge * 2;
|
|
top = origin.y - smallestDistanceToViewportEdge;
|
|
if (height > previousHeight && !this._isInitialRender && !this._growAfterOpen) {
|
|
top = origin.y - previousHeight / 2;
|
|
}
|
|
}
|
|
const isBoundedByRightViewportEdge = position.overlayX === 'start' && !isRtl || position.overlayX === 'end' && isRtl;
|
|
const isBoundedByLeftViewportEdge = position.overlayX === 'end' && !isRtl || position.overlayX === 'start' && isRtl;
|
|
let width, left, right;
|
|
if (isBoundedByLeftViewportEdge) {
|
|
right = viewport.width - origin.x + this._getViewportMarginStart() + this._getViewportMarginEnd();
|
|
width = origin.x - this._getViewportMarginStart();
|
|
} else if (isBoundedByRightViewportEdge) {
|
|
left = origin.x;
|
|
width = viewport.right - origin.x - this._getViewportMarginEnd();
|
|
} else {
|
|
const smallestDistanceToViewportEdge = Math.min(viewport.right - origin.x + viewport.left, origin.x);
|
|
const previousWidth = this._lastBoundingBoxSize.width;
|
|
width = smallestDistanceToViewportEdge * 2;
|
|
left = origin.x - smallestDistanceToViewportEdge;
|
|
if (width > previousWidth && !this._isInitialRender && !this._growAfterOpen) {
|
|
left = origin.x - previousWidth / 2;
|
|
}
|
|
}
|
|
return {
|
|
top: top,
|
|
left: left,
|
|
bottom: bottom,
|
|
right: right,
|
|
width,
|
|
height
|
|
};
|
|
}
|
|
_setBoundingBoxStyles(origin, position) {
|
|
const boundingBoxRect = this._calculateBoundingBoxRect(origin, position);
|
|
if (!this._isInitialRender && !this._growAfterOpen) {
|
|
boundingBoxRect.height = Math.min(boundingBoxRect.height, this._lastBoundingBoxSize.height);
|
|
boundingBoxRect.width = Math.min(boundingBoxRect.width, this._lastBoundingBoxSize.width);
|
|
}
|
|
const styles = {};
|
|
if (this._hasExactPosition()) {
|
|
styles.top = styles.left = '0';
|
|
styles.bottom = styles.right = 'auto';
|
|
styles.maxHeight = styles.maxWidth = '';
|
|
styles.width = styles.height = '100%';
|
|
} else {
|
|
const maxHeight = this._overlayRef.getConfig().maxHeight;
|
|
const maxWidth = this._overlayRef.getConfig().maxWidth;
|
|
styles.width = coerceCssPixelValue(boundingBoxRect.width);
|
|
styles.height = coerceCssPixelValue(boundingBoxRect.height);
|
|
styles.top = coerceCssPixelValue(boundingBoxRect.top) || 'auto';
|
|
styles.bottom = coerceCssPixelValue(boundingBoxRect.bottom) || 'auto';
|
|
styles.left = coerceCssPixelValue(boundingBoxRect.left) || 'auto';
|
|
styles.right = coerceCssPixelValue(boundingBoxRect.right) || 'auto';
|
|
if (position.overlayX === 'center') {
|
|
styles.alignItems = 'center';
|
|
} else {
|
|
styles.alignItems = position.overlayX === 'end' ? 'flex-end' : 'flex-start';
|
|
}
|
|
if (position.overlayY === 'center') {
|
|
styles.justifyContent = 'center';
|
|
} else {
|
|
styles.justifyContent = position.overlayY === 'bottom' ? 'flex-end' : 'flex-start';
|
|
}
|
|
if (maxHeight) {
|
|
styles.maxHeight = coerceCssPixelValue(maxHeight);
|
|
}
|
|
if (maxWidth) {
|
|
styles.maxWidth = coerceCssPixelValue(maxWidth);
|
|
}
|
|
}
|
|
this._lastBoundingBoxSize = boundingBoxRect;
|
|
extendStyles(this._boundingBox.style, styles);
|
|
}
|
|
_resetBoundingBoxStyles() {
|
|
extendStyles(this._boundingBox.style, {
|
|
top: '0',
|
|
left: '0',
|
|
right: '0',
|
|
bottom: '0',
|
|
height: '',
|
|
width: '',
|
|
alignItems: '',
|
|
justifyContent: ''
|
|
});
|
|
}
|
|
_resetOverlayElementStyles() {
|
|
extendStyles(this._pane.style, {
|
|
top: '',
|
|
left: '',
|
|
bottom: '',
|
|
right: '',
|
|
position: '',
|
|
transform: ''
|
|
});
|
|
}
|
|
_setOverlayElementStyles(originPoint, position) {
|
|
const styles = {};
|
|
const hasExactPosition = this._hasExactPosition();
|
|
const hasFlexibleDimensions = this._hasFlexibleDimensions;
|
|
const config = this._overlayRef.getConfig();
|
|
if (hasExactPosition) {
|
|
const scrollPosition = this._viewportRuler.getViewportScrollPosition();
|
|
extendStyles(styles, this._getExactOverlayY(position, originPoint, scrollPosition));
|
|
extendStyles(styles, this._getExactOverlayX(position, originPoint, scrollPosition));
|
|
} else {
|
|
styles.position = 'static';
|
|
}
|
|
let transformString = '';
|
|
let offsetX = this._getOffset(position, 'x');
|
|
let offsetY = this._getOffset(position, 'y');
|
|
if (offsetX) {
|
|
transformString += `translateX(${offsetX}px) `;
|
|
}
|
|
if (offsetY) {
|
|
transformString += `translateY(${offsetY}px)`;
|
|
}
|
|
styles.transform = transformString.trim();
|
|
if (config.maxHeight) {
|
|
if (hasExactPosition) {
|
|
styles.maxHeight = coerceCssPixelValue(config.maxHeight);
|
|
} else if (hasFlexibleDimensions) {
|
|
styles.maxHeight = '';
|
|
}
|
|
}
|
|
if (config.maxWidth) {
|
|
if (hasExactPosition) {
|
|
styles.maxWidth = coerceCssPixelValue(config.maxWidth);
|
|
} else if (hasFlexibleDimensions) {
|
|
styles.maxWidth = '';
|
|
}
|
|
}
|
|
extendStyles(this._pane.style, styles);
|
|
}
|
|
_getExactOverlayY(position, originPoint, scrollPosition) {
|
|
let styles = {
|
|
top: '',
|
|
bottom: ''
|
|
};
|
|
let overlayPoint = this._getOverlayPoint(originPoint, this._overlayRect, position);
|
|
if (this._isPushed) {
|
|
overlayPoint = this._pushOverlayOnScreen(overlayPoint, this._overlayRect, scrollPosition);
|
|
}
|
|
if (position.overlayY === 'bottom') {
|
|
const documentHeight = this._document.documentElement.clientHeight;
|
|
styles.bottom = `${documentHeight - (overlayPoint.y + this._overlayRect.height)}px`;
|
|
} else {
|
|
styles.top = coerceCssPixelValue(overlayPoint.y);
|
|
}
|
|
return styles;
|
|
}
|
|
_getExactOverlayX(position, originPoint, scrollPosition) {
|
|
let styles = {
|
|
left: '',
|
|
right: ''
|
|
};
|
|
let overlayPoint = this._getOverlayPoint(originPoint, this._overlayRect, position);
|
|
if (this._isPushed) {
|
|
overlayPoint = this._pushOverlayOnScreen(overlayPoint, this._overlayRect, scrollPosition);
|
|
}
|
|
let horizontalStyleProperty;
|
|
if (this._isRtl()) {
|
|
horizontalStyleProperty = position.overlayX === 'end' ? 'left' : 'right';
|
|
} else {
|
|
horizontalStyleProperty = position.overlayX === 'end' ? 'right' : 'left';
|
|
}
|
|
if (horizontalStyleProperty === 'right') {
|
|
const documentWidth = this._document.documentElement.clientWidth;
|
|
styles.right = `${documentWidth - (overlayPoint.x + this._overlayRect.width)}px`;
|
|
} else {
|
|
styles.left = coerceCssPixelValue(overlayPoint.x);
|
|
}
|
|
return styles;
|
|
}
|
|
_getScrollVisibility() {
|
|
const originBounds = this._getOriginRect();
|
|
const overlayBounds = this._pane.getBoundingClientRect();
|
|
const scrollContainerBounds = this._scrollables.map(scrollable => {
|
|
return scrollable.getElementRef().nativeElement.getBoundingClientRect();
|
|
});
|
|
return {
|
|
isOriginClipped: isElementClippedByScrolling(originBounds, scrollContainerBounds),
|
|
isOriginOutsideView: isElementScrolledOutsideView(originBounds, scrollContainerBounds),
|
|
isOverlayClipped: isElementClippedByScrolling(overlayBounds, scrollContainerBounds),
|
|
isOverlayOutsideView: isElementScrolledOutsideView(overlayBounds, scrollContainerBounds)
|
|
};
|
|
}
|
|
_subtractOverflows(length, ...overflows) {
|
|
return overflows.reduce((currentValue, currentOverflow) => {
|
|
return currentValue - Math.max(currentOverflow, 0);
|
|
}, length);
|
|
}
|
|
_getNarrowedViewportRect() {
|
|
const width = this._document.documentElement.clientWidth;
|
|
const height = this._document.documentElement.clientHeight;
|
|
const scrollPosition = this._viewportRuler.getViewportScrollPosition();
|
|
return {
|
|
top: scrollPosition.top + this._getViewportMarginTop(),
|
|
left: scrollPosition.left + this._getViewportMarginStart(),
|
|
right: scrollPosition.left + width - this._getViewportMarginEnd(),
|
|
bottom: scrollPosition.top + height - this._getViewportMarginBottom(),
|
|
width: width - this._getViewportMarginStart() - this._getViewportMarginEnd(),
|
|
height: height - this._getViewportMarginTop() - this._getViewportMarginBottom()
|
|
};
|
|
}
|
|
_isRtl() {
|
|
return this._overlayRef.getDirection() === 'rtl';
|
|
}
|
|
_hasExactPosition() {
|
|
return !this._hasFlexibleDimensions || this._isPushed;
|
|
}
|
|
_getOffset(position, axis) {
|
|
if (axis === 'x') {
|
|
return position.offsetX == null ? this._offsetX : position.offsetX;
|
|
}
|
|
return position.offsetY == null ? this._offsetY : position.offsetY;
|
|
}
|
|
_validatePositions() {
|
|
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
if (!this._preferredPositions.length) {
|
|
throw Error('FlexibleConnectedPositionStrategy: At least one position is required.');
|
|
}
|
|
this._preferredPositions.forEach(pair => {
|
|
validateHorizontalPosition('originX', pair.originX);
|
|
validateVerticalPosition('originY', pair.originY);
|
|
validateHorizontalPosition('overlayX', pair.overlayX);
|
|
validateVerticalPosition('overlayY', pair.overlayY);
|
|
});
|
|
}
|
|
}
|
|
_addPanelClasses(cssClasses) {
|
|
if (this._pane) {
|
|
coerceArray(cssClasses).forEach(cssClass => {
|
|
if (cssClass !== '' && this._appliedPanelClasses.indexOf(cssClass) === -1) {
|
|
this._appliedPanelClasses.push(cssClass);
|
|
this._pane.classList.add(cssClass);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
_clearPanelClasses() {
|
|
if (this._pane) {
|
|
this._appliedPanelClasses.forEach(cssClass => {
|
|
this._pane.classList.remove(cssClass);
|
|
});
|
|
this._appliedPanelClasses = [];
|
|
}
|
|
}
|
|
_getViewportMarginStart() {
|
|
if (typeof this._viewportMargin === 'number') return this._viewportMargin;
|
|
return this._viewportMargin?.start ?? 0;
|
|
}
|
|
_getViewportMarginEnd() {
|
|
if (typeof this._viewportMargin === 'number') return this._viewportMargin;
|
|
return this._viewportMargin?.end ?? 0;
|
|
}
|
|
_getViewportMarginTop() {
|
|
if (typeof this._viewportMargin === 'number') return this._viewportMargin;
|
|
return this._viewportMargin?.top ?? 0;
|
|
}
|
|
_getViewportMarginBottom() {
|
|
if (typeof this._viewportMargin === 'number') return this._viewportMargin;
|
|
return this._viewportMargin?.bottom ?? 0;
|
|
}
|
|
_getOriginRect() {
|
|
const origin = this._origin;
|
|
if (origin instanceof ElementRef) {
|
|
return origin.nativeElement.getBoundingClientRect();
|
|
}
|
|
if (origin instanceof Element) {
|
|
return origin.getBoundingClientRect();
|
|
}
|
|
const width = origin.width || 0;
|
|
const height = origin.height || 0;
|
|
return {
|
|
top: origin.y,
|
|
bottom: origin.y + height,
|
|
left: origin.x,
|
|
right: origin.x + width,
|
|
height,
|
|
width
|
|
};
|
|
}
|
|
_getContainerRect() {
|
|
const isInlinePopover = this._overlayRef.getConfig().usePopover && this._popoverLocation !== 'global';
|
|
const element = this._overlayContainer.getContainerElement();
|
|
if (isInlinePopover) {
|
|
element.style.display = 'block';
|
|
}
|
|
const dimensions = element.getBoundingClientRect();
|
|
if (isInlinePopover) {
|
|
element.style.display = '';
|
|
}
|
|
return dimensions;
|
|
}
|
|
}
|
|
function extendStyles(destination, source) {
|
|
for (let key in source) {
|
|
if (source.hasOwnProperty(key)) {
|
|
destination[key] = source[key];
|
|
}
|
|
}
|
|
return destination;
|
|
}
|
|
function getPixelValue(input) {
|
|
if (typeof input !== 'number' && input != null) {
|
|
const [value, units] = input.split(cssUnitPattern);
|
|
return !units || units === 'px' ? parseFloat(value) : null;
|
|
}
|
|
return input || null;
|
|
}
|
|
function getRoundedBoundingClientRect(clientRect) {
|
|
return {
|
|
top: Math.floor(clientRect.top),
|
|
right: Math.floor(clientRect.right),
|
|
bottom: Math.floor(clientRect.bottom),
|
|
left: Math.floor(clientRect.left),
|
|
width: Math.floor(clientRect.width),
|
|
height: Math.floor(clientRect.height)
|
|
};
|
|
}
|
|
function compareScrollVisibility(a, b) {
|
|
if (a === b) {
|
|
return true;
|
|
}
|
|
return a.isOriginClipped === b.isOriginClipped && a.isOriginOutsideView === b.isOriginOutsideView && a.isOverlayClipped === b.isOverlayClipped && a.isOverlayOutsideView === b.isOverlayOutsideView;
|
|
}
|
|
const STANDARD_DROPDOWN_BELOW_POSITIONS = [{
|
|
originX: 'start',
|
|
originY: 'bottom',
|
|
overlayX: 'start',
|
|
overlayY: 'top'
|
|
}, {
|
|
originX: 'start',
|
|
originY: 'top',
|
|
overlayX: 'start',
|
|
overlayY: 'bottom'
|
|
}, {
|
|
originX: 'end',
|
|
originY: 'bottom',
|
|
overlayX: 'end',
|
|
overlayY: 'top'
|
|
}, {
|
|
originX: 'end',
|
|
originY: 'top',
|
|
overlayX: 'end',
|
|
overlayY: 'bottom'
|
|
}];
|
|
const STANDARD_DROPDOWN_ADJACENT_POSITIONS = [{
|
|
originX: 'end',
|
|
originY: 'top',
|
|
overlayX: 'start',
|
|
overlayY: 'top'
|
|
}, {
|
|
originX: 'end',
|
|
originY: 'bottom',
|
|
overlayX: 'start',
|
|
overlayY: 'bottom'
|
|
}, {
|
|
originX: 'start',
|
|
originY: 'top',
|
|
overlayX: 'end',
|
|
overlayY: 'top'
|
|
}, {
|
|
originX: 'start',
|
|
originY: 'bottom',
|
|
overlayX: 'end',
|
|
overlayY: 'bottom'
|
|
}];
|
|
|
|
const wrapperClass = 'cdk-global-overlay-wrapper';
|
|
function createGlobalPositionStrategy(_injector) {
|
|
return new GlobalPositionStrategy();
|
|
}
|
|
class GlobalPositionStrategy {
|
|
_overlayRef;
|
|
_cssPosition = 'static';
|
|
_topOffset = '';
|
|
_bottomOffset = '';
|
|
_alignItems = '';
|
|
_xPosition = '';
|
|
_xOffset = '';
|
|
_width = '';
|
|
_height = '';
|
|
_isDisposed = false;
|
|
attach(overlayRef) {
|
|
const config = overlayRef.getConfig();
|
|
this._overlayRef = overlayRef;
|
|
if (this._width && !config.width) {
|
|
overlayRef.updateSize({
|
|
width: this._width
|
|
});
|
|
}
|
|
if (this._height && !config.height) {
|
|
overlayRef.updateSize({
|
|
height: this._height
|
|
});
|
|
}
|
|
overlayRef.hostElement.classList.add(wrapperClass);
|
|
this._isDisposed = false;
|
|
}
|
|
top(value = '') {
|
|
this._bottomOffset = '';
|
|
this._topOffset = value;
|
|
this._alignItems = 'flex-start';
|
|
return this;
|
|
}
|
|
left(value = '') {
|
|
this._xOffset = value;
|
|
this._xPosition = 'left';
|
|
return this;
|
|
}
|
|
bottom(value = '') {
|
|
this._topOffset = '';
|
|
this._bottomOffset = value;
|
|
this._alignItems = 'flex-end';
|
|
return this;
|
|
}
|
|
right(value = '') {
|
|
this._xOffset = value;
|
|
this._xPosition = 'right';
|
|
return this;
|
|
}
|
|
start(value = '') {
|
|
this._xOffset = value;
|
|
this._xPosition = 'start';
|
|
return this;
|
|
}
|
|
end(value = '') {
|
|
this._xOffset = value;
|
|
this._xPosition = 'end';
|
|
return this;
|
|
}
|
|
width(value = '') {
|
|
if (this._overlayRef) {
|
|
this._overlayRef.updateSize({
|
|
width: value
|
|
});
|
|
} else {
|
|
this._width = value;
|
|
}
|
|
return this;
|
|
}
|
|
height(value = '') {
|
|
if (this._overlayRef) {
|
|
this._overlayRef.updateSize({
|
|
height: value
|
|
});
|
|
} else {
|
|
this._height = value;
|
|
}
|
|
return this;
|
|
}
|
|
centerHorizontally(offset = '') {
|
|
this.left(offset);
|
|
this._xPosition = 'center';
|
|
return this;
|
|
}
|
|
centerVertically(offset = '') {
|
|
this.top(offset);
|
|
this._alignItems = 'center';
|
|
return this;
|
|
}
|
|
apply() {
|
|
if (!this._overlayRef || !this._overlayRef.hasAttached()) {
|
|
return;
|
|
}
|
|
const styles = this._overlayRef.overlayElement.style;
|
|
const parentStyles = this._overlayRef.hostElement.style;
|
|
const config = this._overlayRef.getConfig();
|
|
const {
|
|
width,
|
|
height,
|
|
maxWidth,
|
|
maxHeight
|
|
} = config;
|
|
const shouldBeFlushHorizontally = (width === '100%' || width === '100vw') && (!maxWidth || maxWidth === '100%' || maxWidth === '100vw');
|
|
const shouldBeFlushVertically = (height === '100%' || height === '100vh') && (!maxHeight || maxHeight === '100%' || maxHeight === '100vh');
|
|
const xPosition = this._xPosition;
|
|
const xOffset = this._xOffset;
|
|
const isRtl = this._overlayRef.getConfig().direction === 'rtl';
|
|
let marginLeft = '';
|
|
let marginRight = '';
|
|
let justifyContent = '';
|
|
if (shouldBeFlushHorizontally) {
|
|
justifyContent = 'flex-start';
|
|
} else if (xPosition === 'center') {
|
|
justifyContent = 'center';
|
|
if (isRtl) {
|
|
marginRight = xOffset;
|
|
} else {
|
|
marginLeft = xOffset;
|
|
}
|
|
} else if (isRtl) {
|
|
if (xPosition === 'left' || xPosition === 'end') {
|
|
justifyContent = 'flex-end';
|
|
marginLeft = xOffset;
|
|
} else if (xPosition === 'right' || xPosition === 'start') {
|
|
justifyContent = 'flex-start';
|
|
marginRight = xOffset;
|
|
}
|
|
} else if (xPosition === 'left' || xPosition === 'start') {
|
|
justifyContent = 'flex-start';
|
|
marginLeft = xOffset;
|
|
} else if (xPosition === 'right' || xPosition === 'end') {
|
|
justifyContent = 'flex-end';
|
|
marginRight = xOffset;
|
|
}
|
|
styles.position = this._cssPosition;
|
|
styles.marginLeft = shouldBeFlushHorizontally ? '0' : marginLeft;
|
|
styles.marginTop = shouldBeFlushVertically ? '0' : this._topOffset;
|
|
styles.marginBottom = this._bottomOffset;
|
|
styles.marginRight = shouldBeFlushHorizontally ? '0' : marginRight;
|
|
parentStyles.justifyContent = justifyContent;
|
|
parentStyles.alignItems = shouldBeFlushVertically ? 'flex-start' : this._alignItems;
|
|
}
|
|
dispose() {
|
|
if (this._isDisposed || !this._overlayRef) {
|
|
return;
|
|
}
|
|
const styles = this._overlayRef.overlayElement.style;
|
|
const parent = this._overlayRef.hostElement;
|
|
const parentStyles = parent.style;
|
|
parent.classList.remove(wrapperClass);
|
|
parentStyles.justifyContent = parentStyles.alignItems = styles.marginTop = styles.marginBottom = styles.marginLeft = styles.marginRight = styles.position = '';
|
|
this._overlayRef = null;
|
|
this._isDisposed = true;
|
|
}
|
|
}
|
|
|
|
class OverlayPositionBuilder {
|
|
_injector = inject(Injector);
|
|
constructor() {}
|
|
global() {
|
|
return createGlobalPositionStrategy();
|
|
}
|
|
flexibleConnectedTo(origin) {
|
|
return createFlexibleConnectedPositionStrategy(this._injector, origin);
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayPositionBuilder,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Injectable
|
|
});
|
|
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayPositionBuilder,
|
|
providedIn: 'root'
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayPositionBuilder,
|
|
decorators: [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: 'root'
|
|
}]
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
|
|
const OVERLAY_DEFAULT_CONFIG = new InjectionToken('OVERLAY_DEFAULT_CONFIG');
|
|
function createOverlayRef(injector, config) {
|
|
injector.get(_CdkPrivateStyleLoader).load(_CdkOverlayStyleLoader);
|
|
const overlayContainer = injector.get(OverlayContainer);
|
|
const doc = injector.get(DOCUMENT);
|
|
const idGenerator = injector.get(_IdGenerator);
|
|
const appRef = injector.get(ApplicationRef);
|
|
const directionality = injector.get(Directionality);
|
|
const renderer = injector.get(Renderer2, null, {
|
|
optional: true
|
|
}) || injector.get(RendererFactory2).createRenderer(null, null);
|
|
const overlayConfig = new OverlayConfig(config);
|
|
const defaultUsePopover = injector.get(OVERLAY_DEFAULT_CONFIG, null, {
|
|
optional: true
|
|
})?.usePopover ?? true;
|
|
overlayConfig.direction = overlayConfig.direction || directionality.value;
|
|
if (!('showPopover' in doc.body)) {
|
|
overlayConfig.usePopover = false;
|
|
} else {
|
|
overlayConfig.usePopover = config?.usePopover ?? defaultUsePopover;
|
|
}
|
|
const pane = doc.createElement('div');
|
|
const host = doc.createElement('div');
|
|
pane.id = idGenerator.getId('cdk-overlay-');
|
|
pane.classList.add('cdk-overlay-pane');
|
|
host.appendChild(pane);
|
|
if (overlayConfig.usePopover) {
|
|
host.setAttribute('popover', 'manual');
|
|
host.classList.add('cdk-overlay-popover');
|
|
}
|
|
const customInsertionPoint = overlayConfig.usePopover ? overlayConfig.positionStrategy?.getPopoverInsertionPoint?.() : null;
|
|
if (isElement(customInsertionPoint)) {
|
|
customInsertionPoint.after(host);
|
|
} else if (customInsertionPoint?.type === 'parent') {
|
|
customInsertionPoint.element.appendChild(host);
|
|
} else {
|
|
overlayContainer.getContainerElement().appendChild(host);
|
|
}
|
|
return new OverlayRef(new DomPortalOutlet(pane, appRef, injector), host, pane, overlayConfig, injector.get(NgZone), injector.get(OverlayKeyboardDispatcher), doc, injector.get(Location), injector.get(OverlayOutsideClickDispatcher), config?.disableAnimations ?? injector.get(ANIMATION_MODULE_TYPE, null, {
|
|
optional: true
|
|
}) === 'NoopAnimations', injector.get(EnvironmentInjector), renderer);
|
|
}
|
|
class Overlay {
|
|
scrollStrategies = inject(ScrollStrategyOptions);
|
|
_positionBuilder = inject(OverlayPositionBuilder);
|
|
_injector = inject(Injector);
|
|
constructor() {}
|
|
create(config) {
|
|
return createOverlayRef(this._injector, config);
|
|
}
|
|
position() {
|
|
return this._positionBuilder;
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: Overlay,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Injectable
|
|
});
|
|
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: Overlay,
|
|
providedIn: 'root'
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: Overlay,
|
|
decorators: [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: 'root'
|
|
}]
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
|
|
const defaultPositionList = [{
|
|
originX: 'start',
|
|
originY: 'bottom',
|
|
overlayX: 'start',
|
|
overlayY: 'top'
|
|
}, {
|
|
originX: 'start',
|
|
originY: 'top',
|
|
overlayX: 'start',
|
|
overlayY: 'bottom'
|
|
}, {
|
|
originX: 'end',
|
|
originY: 'top',
|
|
overlayX: 'end',
|
|
overlayY: 'bottom'
|
|
}, {
|
|
originX: 'end',
|
|
originY: 'bottom',
|
|
overlayX: 'end',
|
|
overlayY: 'top'
|
|
}];
|
|
const CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY = new InjectionToken('cdk-connected-overlay-scroll-strategy', {
|
|
providedIn: 'root',
|
|
factory: () => {
|
|
const injector = inject(Injector);
|
|
return () => createRepositionScrollStrategy(injector);
|
|
}
|
|
});
|
|
class CdkOverlayOrigin {
|
|
elementRef = inject(ElementRef);
|
|
constructor() {}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkOverlayOrigin,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Directive
|
|
});
|
|
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
type: CdkOverlayOrigin,
|
|
isStandalone: true,
|
|
selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]",
|
|
exportAs: ["cdkOverlayOrigin"],
|
|
ngImport: i0
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkOverlayOrigin,
|
|
decorators: [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: '[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]',
|
|
exportAs: 'cdkOverlayOrigin'
|
|
}]
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
const CDK_CONNECTED_OVERLAY_DEFAULT_CONFIG = new InjectionToken('cdk-connected-overlay-default-config');
|
|
class CdkConnectedOverlay {
|
|
_dir = inject(Directionality, {
|
|
optional: true
|
|
});
|
|
_injector = inject(Injector);
|
|
_overlayRef;
|
|
_templatePortal;
|
|
_backdropSubscription = Subscription.EMPTY;
|
|
_attachSubscription = Subscription.EMPTY;
|
|
_detachSubscription = Subscription.EMPTY;
|
|
_positionSubscription = Subscription.EMPTY;
|
|
_offsetX;
|
|
_offsetY;
|
|
_position;
|
|
_scrollStrategyFactory = inject(CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY);
|
|
_ngZone = inject(NgZone);
|
|
origin;
|
|
positions;
|
|
positionStrategy;
|
|
get offsetX() {
|
|
return this._offsetX;
|
|
}
|
|
set offsetX(offsetX) {
|
|
this._offsetX = offsetX;
|
|
if (this._position) {
|
|
this._updatePositionStrategy(this._position);
|
|
}
|
|
}
|
|
get offsetY() {
|
|
return this._offsetY;
|
|
}
|
|
set offsetY(offsetY) {
|
|
this._offsetY = offsetY;
|
|
if (this._position) {
|
|
this._updatePositionStrategy(this._position);
|
|
}
|
|
}
|
|
width;
|
|
height;
|
|
minWidth;
|
|
minHeight;
|
|
backdropClass;
|
|
panelClass;
|
|
viewportMargin = 0;
|
|
scrollStrategy;
|
|
open = false;
|
|
disableClose = false;
|
|
transformOriginSelector;
|
|
hasBackdrop = false;
|
|
lockPosition = false;
|
|
flexibleDimensions = false;
|
|
growAfterOpen = false;
|
|
push = false;
|
|
disposeOnNavigation = false;
|
|
usePopover;
|
|
matchWidth = false;
|
|
set _config(value) {
|
|
if (typeof value !== 'string') {
|
|
this._assignConfig(value);
|
|
}
|
|
}
|
|
backdropClick = new EventEmitter();
|
|
positionChange = new EventEmitter();
|
|
attach = new EventEmitter();
|
|
detach = new EventEmitter();
|
|
overlayKeydown = new EventEmitter();
|
|
overlayOutsideClick = new EventEmitter();
|
|
constructor() {
|
|
const templateRef = inject(TemplateRef);
|
|
const viewContainerRef = inject(ViewContainerRef);
|
|
const defaultConfig = inject(CDK_CONNECTED_OVERLAY_DEFAULT_CONFIG, {
|
|
optional: true
|
|
});
|
|
const globalConfig = inject(OVERLAY_DEFAULT_CONFIG, {
|
|
optional: true
|
|
});
|
|
this.usePopover = globalConfig?.usePopover === false ? null : 'global';
|
|
this._templatePortal = new TemplatePortal(templateRef, viewContainerRef);
|
|
this.scrollStrategy = this._scrollStrategyFactory();
|
|
if (defaultConfig) {
|
|
this._assignConfig(defaultConfig);
|
|
}
|
|
}
|
|
get overlayRef() {
|
|
return this._overlayRef;
|
|
}
|
|
get dir() {
|
|
return this._dir ? this._dir.value : 'ltr';
|
|
}
|
|
ngOnDestroy() {
|
|
this._attachSubscription.unsubscribe();
|
|
this._detachSubscription.unsubscribe();
|
|
this._backdropSubscription.unsubscribe();
|
|
this._positionSubscription.unsubscribe();
|
|
this._overlayRef?.dispose();
|
|
}
|
|
ngOnChanges(changes) {
|
|
if (this._position) {
|
|
this._updatePositionStrategy(this._position);
|
|
this._overlayRef?.updateSize({
|
|
width: this._getWidth(),
|
|
minWidth: this.minWidth,
|
|
height: this.height,
|
|
minHeight: this.minHeight
|
|
});
|
|
if (changes['origin'] && this.open) {
|
|
this._position.apply();
|
|
}
|
|
}
|
|
if (changes['open']) {
|
|
this.open ? this.attachOverlay() : this.detachOverlay();
|
|
}
|
|
}
|
|
_createOverlay() {
|
|
if (!this.positions || !this.positions.length) {
|
|
this.positions = defaultPositionList;
|
|
}
|
|
const overlayRef = this._overlayRef = createOverlayRef(this._injector, this._buildConfig());
|
|
this._attachSubscription = overlayRef.attachments().subscribe(() => this.attach.emit());
|
|
this._detachSubscription = overlayRef.detachments().subscribe(() => this.detach.emit());
|
|
overlayRef.keydownEvents().subscribe(event => {
|
|
this.overlayKeydown.next(event);
|
|
if (event.keyCode === ESCAPE && !this.disableClose && !hasModifierKey(event)) {
|
|
event.preventDefault();
|
|
this.detachOverlay();
|
|
}
|
|
});
|
|
this._overlayRef.outsidePointerEvents().subscribe(event => {
|
|
const origin = this._getOriginElement();
|
|
const target = _getEventTarget(event);
|
|
if (!origin || origin !== target && !origin.contains(target)) {
|
|
this.overlayOutsideClick.next(event);
|
|
}
|
|
});
|
|
}
|
|
_buildConfig() {
|
|
const positionStrategy = this._position = this.positionStrategy || this._createPositionStrategy();
|
|
const overlayConfig = new OverlayConfig({
|
|
direction: this._dir || 'ltr',
|
|
positionStrategy,
|
|
scrollStrategy: this.scrollStrategy,
|
|
hasBackdrop: this.hasBackdrop,
|
|
disposeOnNavigation: this.disposeOnNavigation,
|
|
usePopover: !!this.usePopover
|
|
});
|
|
if (this.height || this.height === 0) {
|
|
overlayConfig.height = this.height;
|
|
}
|
|
if (this.minWidth || this.minWidth === 0) {
|
|
overlayConfig.minWidth = this.minWidth;
|
|
}
|
|
if (this.minHeight || this.minHeight === 0) {
|
|
overlayConfig.minHeight = this.minHeight;
|
|
}
|
|
if (this.backdropClass) {
|
|
overlayConfig.backdropClass = this.backdropClass;
|
|
}
|
|
if (this.panelClass) {
|
|
overlayConfig.panelClass = this.panelClass;
|
|
}
|
|
return overlayConfig;
|
|
}
|
|
_updatePositionStrategy(positionStrategy) {
|
|
const positions = this.positions.map(currentPosition => ({
|
|
originX: currentPosition.originX,
|
|
originY: currentPosition.originY,
|
|
overlayX: currentPosition.overlayX,
|
|
overlayY: currentPosition.overlayY,
|
|
offsetX: currentPosition.offsetX || this.offsetX,
|
|
offsetY: currentPosition.offsetY || this.offsetY,
|
|
panelClass: currentPosition.panelClass || undefined
|
|
}));
|
|
return positionStrategy.setOrigin(this._getOrigin()).withPositions(positions).withFlexibleDimensions(this.flexibleDimensions).withPush(this.push).withGrowAfterOpen(this.growAfterOpen).withViewportMargin(this.viewportMargin).withLockedPosition(this.lockPosition).withTransformOriginOn(this.transformOriginSelector).withPopoverLocation(this.usePopover === null ? 'global' : this.usePopover);
|
|
}
|
|
_createPositionStrategy() {
|
|
const strategy = createFlexibleConnectedPositionStrategy(this._injector, this._getOrigin());
|
|
this._updatePositionStrategy(strategy);
|
|
return strategy;
|
|
}
|
|
_getOrigin() {
|
|
if (this.origin instanceof CdkOverlayOrigin) {
|
|
return this.origin.elementRef;
|
|
} else {
|
|
return this.origin;
|
|
}
|
|
}
|
|
_getOriginElement() {
|
|
if (this.origin instanceof CdkOverlayOrigin) {
|
|
return this.origin.elementRef.nativeElement;
|
|
}
|
|
if (this.origin instanceof ElementRef) {
|
|
return this.origin.nativeElement;
|
|
}
|
|
if (typeof Element !== 'undefined' && this.origin instanceof Element) {
|
|
return this.origin;
|
|
}
|
|
return null;
|
|
}
|
|
_getWidth() {
|
|
if (this.width) {
|
|
return this.width;
|
|
}
|
|
return this.matchWidth ? this._getOriginElement()?.getBoundingClientRect?.().width : undefined;
|
|
}
|
|
attachOverlay() {
|
|
if (!this._overlayRef) {
|
|
this._createOverlay();
|
|
}
|
|
const ref = this._overlayRef;
|
|
ref.getConfig().hasBackdrop = this.hasBackdrop;
|
|
ref.updateSize({
|
|
width: this._getWidth()
|
|
});
|
|
if (!ref.hasAttached()) {
|
|
ref.attach(this._templatePortal);
|
|
}
|
|
if (this.hasBackdrop) {
|
|
this._backdropSubscription = ref.backdropClick().subscribe(event => this.backdropClick.emit(event));
|
|
} else {
|
|
this._backdropSubscription.unsubscribe();
|
|
}
|
|
this._positionSubscription.unsubscribe();
|
|
if (this.positionChange.observers.length > 0) {
|
|
this._positionSubscription = this._position.positionChanges.pipe(takeWhile(() => this.positionChange.observers.length > 0)).subscribe(position => {
|
|
this._ngZone.run(() => this.positionChange.emit(position));
|
|
if (this.positionChange.observers.length === 0) {
|
|
this._positionSubscription.unsubscribe();
|
|
}
|
|
});
|
|
}
|
|
this.open = true;
|
|
}
|
|
detachOverlay() {
|
|
this._overlayRef?.detach();
|
|
this._backdropSubscription.unsubscribe();
|
|
this._positionSubscription.unsubscribe();
|
|
this.open = false;
|
|
}
|
|
_assignConfig(config) {
|
|
this.origin = config.origin ?? this.origin;
|
|
this.positions = config.positions ?? this.positions;
|
|
this.positionStrategy = config.positionStrategy ?? this.positionStrategy;
|
|
this.offsetX = config.offsetX ?? this.offsetX;
|
|
this.offsetY = config.offsetY ?? this.offsetY;
|
|
this.width = config.width ?? this.width;
|
|
this.height = config.height ?? this.height;
|
|
this.minWidth = config.minWidth ?? this.minWidth;
|
|
this.minHeight = config.minHeight ?? this.minHeight;
|
|
this.backdropClass = config.backdropClass ?? this.backdropClass;
|
|
this.panelClass = config.panelClass ?? this.panelClass;
|
|
this.viewportMargin = config.viewportMargin ?? this.viewportMargin;
|
|
this.scrollStrategy = config.scrollStrategy ?? this.scrollStrategy;
|
|
this.disableClose = config.disableClose ?? this.disableClose;
|
|
this.transformOriginSelector = config.transformOriginSelector ?? this.transformOriginSelector;
|
|
this.hasBackdrop = config.hasBackdrop ?? this.hasBackdrop;
|
|
this.lockPosition = config.lockPosition ?? this.lockPosition;
|
|
this.flexibleDimensions = config.flexibleDimensions ?? this.flexibleDimensions;
|
|
this.growAfterOpen = config.growAfterOpen ?? this.growAfterOpen;
|
|
this.push = config.push ?? this.push;
|
|
this.disposeOnNavigation = config.disposeOnNavigation ?? this.disposeOnNavigation;
|
|
this.usePopover = config.usePopover ?? this.usePopover;
|
|
this.matchWidth = config.matchWidth ?? this.matchWidth;
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkConnectedOverlay,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Directive
|
|
});
|
|
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
minVersion: "16.1.0",
|
|
version: "21.0.3",
|
|
type: CdkConnectedOverlay,
|
|
isStandalone: true,
|
|
selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]",
|
|
inputs: {
|
|
origin: ["cdkConnectedOverlayOrigin", "origin"],
|
|
positions: ["cdkConnectedOverlayPositions", "positions"],
|
|
positionStrategy: ["cdkConnectedOverlayPositionStrategy", "positionStrategy"],
|
|
offsetX: ["cdkConnectedOverlayOffsetX", "offsetX"],
|
|
offsetY: ["cdkConnectedOverlayOffsetY", "offsetY"],
|
|
width: ["cdkConnectedOverlayWidth", "width"],
|
|
height: ["cdkConnectedOverlayHeight", "height"],
|
|
minWidth: ["cdkConnectedOverlayMinWidth", "minWidth"],
|
|
minHeight: ["cdkConnectedOverlayMinHeight", "minHeight"],
|
|
backdropClass: ["cdkConnectedOverlayBackdropClass", "backdropClass"],
|
|
panelClass: ["cdkConnectedOverlayPanelClass", "panelClass"],
|
|
viewportMargin: ["cdkConnectedOverlayViewportMargin", "viewportMargin"],
|
|
scrollStrategy: ["cdkConnectedOverlayScrollStrategy", "scrollStrategy"],
|
|
open: ["cdkConnectedOverlayOpen", "open"],
|
|
disableClose: ["cdkConnectedOverlayDisableClose", "disableClose"],
|
|
transformOriginSelector: ["cdkConnectedOverlayTransformOriginOn", "transformOriginSelector"],
|
|
hasBackdrop: ["cdkConnectedOverlayHasBackdrop", "hasBackdrop", booleanAttribute],
|
|
lockPosition: ["cdkConnectedOverlayLockPosition", "lockPosition", booleanAttribute],
|
|
flexibleDimensions: ["cdkConnectedOverlayFlexibleDimensions", "flexibleDimensions", booleanAttribute],
|
|
growAfterOpen: ["cdkConnectedOverlayGrowAfterOpen", "growAfterOpen", booleanAttribute],
|
|
push: ["cdkConnectedOverlayPush", "push", booleanAttribute],
|
|
disposeOnNavigation: ["cdkConnectedOverlayDisposeOnNavigation", "disposeOnNavigation", booleanAttribute],
|
|
usePopover: ["cdkConnectedOverlayUsePopover", "usePopover"],
|
|
matchWidth: ["cdkConnectedOverlayMatchWidth", "matchWidth", booleanAttribute],
|
|
_config: ["cdkConnectedOverlay", "_config"]
|
|
},
|
|
outputs: {
|
|
backdropClick: "backdropClick",
|
|
positionChange: "positionChange",
|
|
attach: "attach",
|
|
detach: "detach",
|
|
overlayKeydown: "overlayKeydown",
|
|
overlayOutsideClick: "overlayOutsideClick"
|
|
},
|
|
exportAs: ["cdkConnectedOverlay"],
|
|
usesOnChanges: true,
|
|
ngImport: i0
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkConnectedOverlay,
|
|
decorators: [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: '[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]',
|
|
exportAs: 'cdkConnectedOverlay'
|
|
}]
|
|
}],
|
|
ctorParameters: () => [],
|
|
propDecorators: {
|
|
origin: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayOrigin']
|
|
}],
|
|
positions: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayPositions']
|
|
}],
|
|
positionStrategy: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayPositionStrategy']
|
|
}],
|
|
offsetX: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayOffsetX']
|
|
}],
|
|
offsetY: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayOffsetY']
|
|
}],
|
|
width: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayWidth']
|
|
}],
|
|
height: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayHeight']
|
|
}],
|
|
minWidth: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayMinWidth']
|
|
}],
|
|
minHeight: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayMinHeight']
|
|
}],
|
|
backdropClass: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayBackdropClass']
|
|
}],
|
|
panelClass: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayPanelClass']
|
|
}],
|
|
viewportMargin: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayViewportMargin']
|
|
}],
|
|
scrollStrategy: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayScrollStrategy']
|
|
}],
|
|
open: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayOpen']
|
|
}],
|
|
disableClose: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayDisableClose']
|
|
}],
|
|
transformOriginSelector: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlayTransformOriginOn']
|
|
}],
|
|
hasBackdrop: [{
|
|
type: Input,
|
|
args: [{
|
|
alias: 'cdkConnectedOverlayHasBackdrop',
|
|
transform: booleanAttribute
|
|
}]
|
|
}],
|
|
lockPosition: [{
|
|
type: Input,
|
|
args: [{
|
|
alias: 'cdkConnectedOverlayLockPosition',
|
|
transform: booleanAttribute
|
|
}]
|
|
}],
|
|
flexibleDimensions: [{
|
|
type: Input,
|
|
args: [{
|
|
alias: 'cdkConnectedOverlayFlexibleDimensions',
|
|
transform: booleanAttribute
|
|
}]
|
|
}],
|
|
growAfterOpen: [{
|
|
type: Input,
|
|
args: [{
|
|
alias: 'cdkConnectedOverlayGrowAfterOpen',
|
|
transform: booleanAttribute
|
|
}]
|
|
}],
|
|
push: [{
|
|
type: Input,
|
|
args: [{
|
|
alias: 'cdkConnectedOverlayPush',
|
|
transform: booleanAttribute
|
|
}]
|
|
}],
|
|
disposeOnNavigation: [{
|
|
type: Input,
|
|
args: [{
|
|
alias: 'cdkConnectedOverlayDisposeOnNavigation',
|
|
transform: booleanAttribute
|
|
}]
|
|
}],
|
|
usePopover: [{
|
|
type: Input,
|
|
args: [{
|
|
alias: 'cdkConnectedOverlayUsePopover'
|
|
}]
|
|
}],
|
|
matchWidth: [{
|
|
type: Input,
|
|
args: [{
|
|
alias: 'cdkConnectedOverlayMatchWidth',
|
|
transform: booleanAttribute
|
|
}]
|
|
}],
|
|
_config: [{
|
|
type: Input,
|
|
args: ['cdkConnectedOverlay']
|
|
}],
|
|
backdropClick: [{
|
|
type: Output
|
|
}],
|
|
positionChange: [{
|
|
type: Output
|
|
}],
|
|
attach: [{
|
|
type: Output
|
|
}],
|
|
detach: [{
|
|
type: Output
|
|
}],
|
|
overlayKeydown: [{
|
|
type: Output
|
|
}],
|
|
overlayOutsideClick: [{
|
|
type: Output
|
|
}]
|
|
}
|
|
});
|
|
|
|
class OverlayModule {
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayModule,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.NgModule
|
|
});
|
|
static ɵmod = i0.ɵɵngDeclareNgModule({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayModule,
|
|
imports: [BidiModule, PortalModule, ScrollingModule, CdkConnectedOverlay, CdkOverlayOrigin],
|
|
exports: [CdkConnectedOverlay, CdkOverlayOrigin, ScrollingModule]
|
|
});
|
|
static ɵinj = i0.ɵɵngDeclareInjector({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayModule,
|
|
providers: [Overlay],
|
|
imports: [BidiModule, PortalModule, ScrollingModule, ScrollingModule]
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: OverlayModule,
|
|
decorators: [{
|
|
type: NgModule,
|
|
args: [{
|
|
imports: [BidiModule, PortalModule, ScrollingModule, CdkConnectedOverlay, CdkOverlayOrigin],
|
|
exports: [CdkConnectedOverlay, CdkOverlayOrigin, ScrollingModule],
|
|
providers: [Overlay]
|
|
}]
|
|
}]
|
|
});
|
|
|
|
export { BlockScrollStrategy, CDK_CONNECTED_OVERLAY_DEFAULT_CONFIG, CdkConnectedOverlay, CdkOverlayOrigin, CloseScrollStrategy, ConnectedOverlayPositionChange, ConnectionPositionPair, FlexibleConnectedPositionStrategy, GlobalPositionStrategy, NoopScrollStrategy, OVERLAY_DEFAULT_CONFIG, Overlay, OverlayConfig, OverlayContainer, OverlayKeyboardDispatcher, OverlayModule, OverlayOutsideClickDispatcher, OverlayPositionBuilder, OverlayRef, RepositionScrollStrategy, STANDARD_DROPDOWN_ADJACENT_POSITIONS, STANDARD_DROPDOWN_BELOW_POSITIONS, ScrollStrategyOptions, ScrollingVisibility, createBlockScrollStrategy, createCloseScrollStrategy, createFlexibleConnectedPositionStrategy, createGlobalPositionStrategy, createNoopScrollStrategy, createOverlayRef, createRepositionScrollStrategy, validateHorizontalPosition, validateVerticalPosition };
|
|
//# sourceMappingURL=_overlay-module-chunk.mjs.map
|
|
|