@angular/cdk
Version:
Angular Material Component Development Kit
1,472 lines (1,456 loc) • 90.4 kB
JavaScript
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.0",
ngImport: i0,
type: ScrollStrategyOptions,
deps: [],
target: i0.ɵɵFactoryTarget.Injectable
});
static ɵprov = i0.ɵɵngDeclareInjectable({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: ScrollStrategyOptions,
providedIn: 'root'
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.0",
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;
isOriginOutsideView;
isOverlayClipped;
isOverlayOutsideView;
}
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;
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.0",
ngImport: i0,
type: BaseOverlayDispatcher,
deps: [],
target: i0.ɵɵFactoryTarget.Injectable
});
static ɵprov = i0.ɵɵngDeclareInjectable({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: BaseOverlayDispatcher,
providedIn: 'root'
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.0",
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.0",
ngImport: i0,
type: OverlayKeyboardDispatcher,
deps: null,
target: i0.ɵɵFactoryTarget.Injectable
});
static ɵprov = i0.ɵɵngDeclareInjectable({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: OverlayKeyboardDispatcher,
providedIn: 'root'
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.0",
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;
_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.0",
ngImport: i0,
type: OverlayOutsideClickDispatcher,
deps: null,
target: i0.ɵɵFactoryTarget.Injectable
});
static ɵprov = i0.ɵɵngDeclareInjectable({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: OverlayOutsideClickDispatcher,
providedIn: 'root'
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.0",
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.0",
ngImport: i0,
type: _CdkOverlayStyleLoader,
deps: [],
target: i0.ɵɵFactoryTarget.Component
});
static ɵcmp = i0.ɵɵngDeclareComponent({
minVersion: "14.0.0",
version: "21.0.0",
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.0",
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.0",
ngImport: i0,
type: OverlayContainer,
deps: [],
target: i0.ɵɵFactoryTarget.Injectable
});
static ɵprov = i0.ɵɵngDeclareInjectable({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: OverlayContainer,
providedIn: 'root'
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.0",
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;
_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) {
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() {
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();
}
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;
_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;
_boundingBox;
_lastPosition;
_lastScrollVisibility;
_positionChanges = new Subject();
_resizeSubscription = Subscription.EMPTY;
_offsetX = 0;
_offsetY = 0;
_transformOriginSelector;
_appliedPanelClasses = [];
_previousPushAmount;
_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._overlayContainer.getContainerElement().getBoundingClientRect();
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._overlayContainer.getContainerElement().getBoundingClientRect();
const originPoint = this._getOriginPoint(this._originRect, this._containerRect, lastPosition);
this._applyPosition(lastPosition, originPoint);
} 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.