import {
ESCAPE,
hasModifierKey
} from "./chunk-JGP5BR6B.js";
import {
BidiModule,
Directionality
} from "./chunk-6NZ2BEBG.js";
import {
Platform,
_getEventTarget,
_isTestEnvironment,
getRtlScrollAxisType,
supportsScrollBehavior
} from "./chunk-IAC53GOD.js";
import {
coerceArray,
coerceCssPixelValue,
coerceElement,
coerceNumberProperty
} from "./chunk-M5GY4FCO.js";
import {
DOCUMENT,
Location
} from "./chunk-OSQBUYO6.js";
import {
ANIMATION_MODULE_TYPE,
ApplicationRef,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ComponentFactoryResolver$1,
ConnectableObservable,
Directive,
ElementRef,
EventEmitter,
Inject,
Injectable,
InjectionToken,
Injector,
Input,
IterableDiffers,
NgModule,
NgZone,
Observable,
Optional,
Output,
SkipSelf,
Subject,
Subscription,
TemplateRef,
ViewChild,
ViewContainerRef,
ViewEncapsulation$1,
animationFrameScheduler,
asapScheduler,
auditTime,
booleanAttribute,
distinctUntilChanged,
filter,
forwardRef,
fromEvent,
inject,
isObservable,
merge,
of,
pairwise,
setClassMetadata,
shareReplay,
startWith,
switchMap,
take,
takeUntil,
takeWhile,
ɵɵInheritDefinitionFeature,
ɵɵInputTransformsFeature,
ɵɵNgOnChangesFeature,
ɵɵProvidersFeature,
ɵɵStandaloneFeature,
ɵɵadvance,
ɵɵclassProp,
ɵɵdefineComponent,
ɵɵdefineDirective,
ɵɵdefineInjectable,
ɵɵdefineInjector,
ɵɵdefineNgModule,
ɵɵdirectiveInject,
ɵɵelement,
ɵɵelementEnd,
ɵɵelementStart,
ɵɵgetInheritedFactory,
ɵɵinject,
ɵɵloadQuery,
ɵɵprojection,
ɵɵprojectionDef,
ɵɵqueryRefresh,
ɵɵstyleProp,
ɵɵviewQuery
} from "./chunk-FGESKT7O.js";
import {
__spreadProps,
__spreadValues
} from "./chunk-HSNDBVJ3.js";
// node_modules/@angular/cdk/fesm2022/collections.mjs
var DataSource = class {
};
function isDataSource(value) {
return value && typeof value.connect === "function" && !(value instanceof ConnectableObservable);
}
var ArrayDataSource = class extends DataSource {
constructor(_data) {
super();
this._data = _data;
}
connect() {
return isObservable(this._data) ? this._data : of(this._data);
}
disconnect() {
}
};
var _RecycleViewRepeaterStrategy = class {
constructor() {
this.viewCacheSize = 20;
this._viewCache = [];
}
/** Apply changes to the DOM. */
applyChanges(changes, viewContainerRef, itemContextFactory, itemValueResolver, itemViewChanged) {
changes.forEachOperation((record, adjustedPreviousIndex, currentIndex) => {
let view;
let operation;
if (record.previousIndex == null) {
const viewArgsFactory = () => itemContextFactory(record, adjustedPreviousIndex, currentIndex);
view = this._insertView(viewArgsFactory, currentIndex, viewContainerRef, itemValueResolver(record));
operation = view ? 1 : 0;
} else if (currentIndex == null) {
this._detachAndCacheView(adjustedPreviousIndex, viewContainerRef);
operation = 3;
} else {
view = this._moveView(adjustedPreviousIndex, currentIndex, viewContainerRef, itemValueResolver(record));
operation = 2;
}
if (itemViewChanged) {
itemViewChanged({
context: view?.context,
operation,
record
});
}
});
}
detach() {
for (const view of this._viewCache) {
view.destroy();
}
this._viewCache = [];
}
/**
* Inserts a view for a new item, either from the cache or by creating a new
* one. Returns `undefined` if the item was inserted into a cached view.
*/
_insertView(viewArgsFactory, currentIndex, viewContainerRef, value) {
const cachedView = this._insertViewFromCache(currentIndex, viewContainerRef);
if (cachedView) {
cachedView.context.$implicit = value;
return void 0;
}
const viewArgs = viewArgsFactory();
return viewContainerRef.createEmbeddedView(viewArgs.templateRef, viewArgs.context, viewArgs.index);
}
/** Detaches the view at the given index and inserts into the view cache. */
_detachAndCacheView(index, viewContainerRef) {
const detachedView = viewContainerRef.detach(index);
this._maybeCacheView(detachedView, viewContainerRef);
}
/** Moves view at the previous index to the current index. */
_moveView(adjustedPreviousIndex, currentIndex, viewContainerRef, value) {
const view = viewContainerRef.get(adjustedPreviousIndex);
viewContainerRef.move(view, currentIndex);
view.context.$implicit = value;
return view;
}
/**
* Cache the given detached view. If the cache is full, the view will be
* destroyed.
*/
_maybeCacheView(view, viewContainerRef) {
if (this._viewCache.length < this.viewCacheSize) {
this._viewCache.push(view);
} else {
const index = viewContainerRef.indexOf(view);
if (index === -1) {
view.destroy();
} else {
viewContainerRef.remove(index);
}
}
}
/** Inserts a recycled view from the cache at the given index. */
_insertViewFromCache(index, viewContainerRef) {
const cachedView = this._viewCache.pop();
if (cachedView) {
viewContainerRef.insert(cachedView, index);
}
return cachedView || null;
}
};
var _UniqueSelectionDispatcher = class _UniqueSelectionDispatcher {
constructor() {
this._listeners = [];
}
/**
* Notify other items that selection for the given name has been set.
* @param id ID of the item.
* @param name Name of the item.
*/
notify(id, name) {
for (let listener of this._listeners) {
listener(id, name);
}
}
/**
* Listen for future changes to item selection.
* @return Function used to deregister listener
*/
listen(listener) {
this._listeners.push(listener);
return () => {
this._listeners = this._listeners.filter((registered) => {
return listener !== registered;
});
};
}
ngOnDestroy() {
this._listeners = [];
}
};
_UniqueSelectionDispatcher.ɵfac = function UniqueSelectionDispatcher_Factory(t) {
return new (t || _UniqueSelectionDispatcher)();
};
_UniqueSelectionDispatcher.ɵprov = ɵɵdefineInjectable({
token: _UniqueSelectionDispatcher,
factory: _UniqueSelectionDispatcher.ɵfac,
providedIn: "root"
});
var UniqueSelectionDispatcher = _UniqueSelectionDispatcher;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(UniqueSelectionDispatcher, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], null, null);
})();
var _VIEW_REPEATER_STRATEGY = new InjectionToken("_ViewRepeater");
// node_modules/@angular/cdk/fesm2022/scrolling.mjs
var _c0 = ["contentWrapper"];
var _c1 = ["*"];
var VIRTUAL_SCROLL_STRATEGY = new InjectionToken("VIRTUAL_SCROLL_STRATEGY");
var FixedSizeVirtualScrollStrategy = class {
/**
* @param itemSize The size of the items in the virtually scrolling list.
* @param minBufferPx The minimum amount of buffer (in pixels) before needing to render more
* @param maxBufferPx The amount of buffer (in pixels) to render when rendering more.
*/
constructor(itemSize, minBufferPx, maxBufferPx) {
this._scrolledIndexChange = new Subject();
this.scrolledIndexChange = this._scrolledIndexChange.pipe(distinctUntilChanged());
this._viewport = null;
this._itemSize = itemSize;
this._minBufferPx = minBufferPx;
this._maxBufferPx = maxBufferPx;
}
/**
* Attaches this scroll strategy to a viewport.
* @param viewport The viewport to attach this strategy to.
*/
attach(viewport) {
this._viewport = viewport;
this._updateTotalContentSize();
this._updateRenderedRange();
}
/** Detaches this scroll strategy from the currently attached viewport. */
detach() {
this._scrolledIndexChange.complete();
this._viewport = null;
}
/**
* Update the item size and buffer size.
* @param itemSize The size of the items in the virtually scrolling list.
* @param minBufferPx The minimum amount of buffer (in pixels) before needing to render more
* @param maxBufferPx The amount of buffer (in pixels) to render when rendering more.
*/
updateItemAndBufferSize(itemSize, minBufferPx, maxBufferPx) {
if (maxBufferPx < minBufferPx && (typeof ngDevMode === "undefined" || ngDevMode)) {
throw Error("CDK virtual scroll: maxBufferPx must be greater than or equal to minBufferPx");
}
this._itemSize = itemSize;
this._minBufferPx = minBufferPx;
this._maxBufferPx = maxBufferPx;
this._updateTotalContentSize();
this._updateRenderedRange();
}
/** @docs-private Implemented as part of VirtualScrollStrategy. */
onContentScrolled() {
this._updateRenderedRange();
}
/** @docs-private Implemented as part of VirtualScrollStrategy. */
onDataLengthChanged() {
this._updateTotalContentSize();
this._updateRenderedRange();
}
/** @docs-private Implemented as part of VirtualScrollStrategy. */
onContentRendered() {
}
/** @docs-private Implemented as part of VirtualScrollStrategy. */
onRenderedOffsetChanged() {
}
/**
* Scroll to the offset for the given index.
* @param index The index of the element to scroll to.
* @param behavior The ScrollBehavior to use when scrolling.
*/
scrollToIndex(index, behavior) {
if (this._viewport) {
this._viewport.scrollToOffset(index * this._itemSize, behavior);
}
}
/** Update the viewport's total content size. */
_updateTotalContentSize() {
if (!this._viewport) {
return;
}
this._viewport.setTotalContentSize(this._viewport.getDataLength() * this._itemSize);
}
/** Update the viewport's rendered range. */
_updateRenderedRange() {
if (!this._viewport) {
return;
}
const renderedRange = this._viewport.getRenderedRange();
const newRange = {
start: renderedRange.start,
end: renderedRange.end
};
const viewportSize = this._viewport.getViewportSize();
const dataLength = this._viewport.getDataLength();
let scrollOffset = this._viewport.measureScrollOffset();
let firstVisibleIndex = this._itemSize > 0 ? scrollOffset / this._itemSize : 0;
if (newRange.end > dataLength) {
const maxVisibleItems = Math.ceil(viewportSize / this._itemSize);
const newVisibleIndex = Math.max(0, Math.min(firstVisibleIndex, dataLength - maxVisibleItems));
if (firstVisibleIndex != newVisibleIndex) {
firstVisibleIndex = newVisibleIndex;
scrollOffset = newVisibleIndex * this._itemSize;
newRange.start = Math.floor(firstVisibleIndex);
}
newRange.end = Math.max(0, Math.min(dataLength, newRange.start + maxVisibleItems));
}
const startBuffer = scrollOffset - newRange.start * this._itemSize;
if (startBuffer < this._minBufferPx && newRange.start != 0) {
const expandStart = Math.ceil((this._maxBufferPx - startBuffer) / this._itemSize);
newRange.start = Math.max(0, newRange.start - expandStart);
newRange.end = Math.min(dataLength, Math.ceil(firstVisibleIndex + (viewportSize + this._minBufferPx) / this._itemSize));
} else {
const endBuffer = newRange.end * this._itemSize - (scrollOffset + viewportSize);
if (endBuffer < this._minBufferPx && newRange.end != dataLength) {
const expandEnd = Math.ceil((this._maxBufferPx - endBuffer) / this._itemSize);
if (expandEnd > 0) {
newRange.end = Math.min(dataLength, newRange.end + expandEnd);
newRange.start = Math.max(0, Math.floor(firstVisibleIndex - this._minBufferPx / this._itemSize));
}
}
}
this._viewport.setRenderedRange(newRange);
this._viewport.setRenderedContentOffset(this._itemSize * newRange.start);
this._scrolledIndexChange.next(Math.floor(firstVisibleIndex));
}
};
function _fixedSizeVirtualScrollStrategyFactory(fixedSizeDir) {
return fixedSizeDir._scrollStrategy;
}
var _CdkFixedSizeVirtualScroll = class _CdkFixedSizeVirtualScroll {
constructor() {
this._itemSize = 20;
this._minBufferPx = 100;
this._maxBufferPx = 200;
this._scrollStrategy = new FixedSizeVirtualScrollStrategy(this.itemSize, this.minBufferPx, this.maxBufferPx);
}
/** The size of the items in the list (in pixels). */
get itemSize() {
return this._itemSize;
}
set itemSize(value) {
this._itemSize = coerceNumberProperty(value);
}
/**
* The minimum amount of buffer rendered beyond the viewport (in pixels).
* If the amount of buffer dips below this number, more items will be rendered. Defaults to 100px.
*/
get minBufferPx() {
return this._minBufferPx;
}
set minBufferPx(value) {
this._minBufferPx = coerceNumberProperty(value);
}
/**
* The number of pixels worth of buffer to render for when rendering new items. Defaults to 200px.
*/
get maxBufferPx() {
return this._maxBufferPx;
}
set maxBufferPx(value) {
this._maxBufferPx = coerceNumberProperty(value);
}
ngOnChanges() {
this._scrollStrategy.updateItemAndBufferSize(this.itemSize, this.minBufferPx, this.maxBufferPx);
}
};
_CdkFixedSizeVirtualScroll.ɵfac = function CdkFixedSizeVirtualScroll_Factory(t) {
return new (t || _CdkFixedSizeVirtualScroll)();
};
_CdkFixedSizeVirtualScroll.ɵdir = ɵɵdefineDirective({
type: _CdkFixedSizeVirtualScroll,
selectors: [["cdk-virtual-scroll-viewport", "itemSize", ""]],
inputs: {
itemSize: "itemSize",
minBufferPx: "minBufferPx",
maxBufferPx: "maxBufferPx"
},
standalone: true,
features: [ɵɵProvidersFeature([{
provide: VIRTUAL_SCROLL_STRATEGY,
useFactory: _fixedSizeVirtualScrollStrategyFactory,
deps: [forwardRef(() => _CdkFixedSizeVirtualScroll)]
}]), ɵɵNgOnChangesFeature]
});
var CdkFixedSizeVirtualScroll = _CdkFixedSizeVirtualScroll;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CdkFixedSizeVirtualScroll, [{
type: Directive,
args: [{
selector: "cdk-virtual-scroll-viewport[itemSize]",
standalone: true,
providers: [{
provide: VIRTUAL_SCROLL_STRATEGY,
useFactory: _fixedSizeVirtualScrollStrategyFactory,
deps: [forwardRef(() => CdkFixedSizeVirtualScroll)]
}]
}]
}], null, {
itemSize: [{
type: Input
}],
minBufferPx: [{
type: Input
}],
maxBufferPx: [{
type: Input
}]
});
})();
var DEFAULT_SCROLL_TIME = 20;
var _ScrollDispatcher = class _ScrollDispatcher {
constructor(_ngZone, _platform, document2) {
this._ngZone = _ngZone;
this._platform = _platform;
this._scrolled = new Subject();
this._globalSubscription = null;
this._scrolledCount = 0;
this.scrollContainers = /* @__PURE__ */ new Map();
this._document = document2;
}
/**
* Registers a scrollable instance with the service and listens for its scrolled events. When the
* scrollable is scrolled, the service emits the event to its scrolled observable.
* @param scrollable Scrollable instance to be registered.
*/
register(scrollable) {
if (!this.scrollContainers.has(scrollable)) {
this.scrollContainers.set(scrollable, scrollable.elementScrolled().subscribe(() => this._scrolled.next(scrollable)));
}
}
/**
* De-registers a Scrollable reference and unsubscribes from its scroll event observable.
* @param scrollable Scrollable instance to be deregistered.
*/
deregister(scrollable) {
const scrollableReference = this.scrollContainers.get(scrollable);
if (scrollableReference) {
scrollableReference.unsubscribe();
this.scrollContainers.delete(scrollable);
}
}
/**
* Returns an observable that emits an event whenever any of the registered Scrollable
* references (or window, document, or body) fire a scrolled event. Can provide a time in ms
* to override the default "throttle" time.
*
* **Note:** in order to avoid hitting change detection for every scroll event,
* all of the events emitted from this stream will be run outside the Angular zone.
* If you need to update any data bindings as a result of a scroll event, you have
* to run the callback using `NgZone.run`.
*/
scrolled(auditTimeInMs = DEFAULT_SCROLL_TIME) {
if (!this._platform.isBrowser) {
return of();
}
return new Observable((observer) => {
if (!this._globalSubscription) {
this._addGlobalListener();
}
const subscription = auditTimeInMs > 0 ? this._scrolled.pipe(auditTime(auditTimeInMs)).subscribe(observer) : this._scrolled.subscribe(observer);
this._scrolledCount++;
return () => {
subscription.unsubscribe();
this._scrolledCount--;
if (!this._scrolledCount) {
this._removeGlobalListener();
}
};
});
}
ngOnDestroy() {
this._removeGlobalListener();
this.scrollContainers.forEach((_, container) => this.deregister(container));
this._scrolled.complete();
}
/**
* Returns an observable that emits whenever any of the
* scrollable ancestors of an element are scrolled.
* @param elementOrElementRef Element whose ancestors to listen for.
* @param auditTimeInMs Time to throttle the scroll events.
*/
ancestorScrolled(elementOrElementRef, auditTimeInMs) {
const ancestors = this.getAncestorScrollContainers(elementOrElementRef);
return this.scrolled(auditTimeInMs).pipe(filter((target) => {
return !target || ancestors.indexOf(target) > -1;
}));
}
/** Returns all registered Scrollables that contain the provided element. */
getAncestorScrollContainers(elementOrElementRef) {
const scrollingContainers = [];
this.scrollContainers.forEach((_subscription, scrollable) => {
if (this._scrollableContainsElement(scrollable, elementOrElementRef)) {
scrollingContainers.push(scrollable);
}
});
return scrollingContainers;
}
/** Use defaultView of injected document if available or fallback to global window reference */
_getWindow() {
return this._document.defaultView || window;
}
/** Returns true if the element is contained within the provided Scrollable. */
_scrollableContainsElement(scrollable, elementOrElementRef) {
let element = coerceElement(elementOrElementRef);
let scrollableElement = scrollable.getElementRef().nativeElement;
do {
if (element == scrollableElement) {
return true;
}
} while (element = element.parentElement);
return false;
}
/** Sets up the global scroll listeners. */
_addGlobalListener() {
this._globalSubscription = this._ngZone.runOutsideAngular(() => {
const window2 = this._getWindow();
return fromEvent(window2.document, "scroll").subscribe(() => this._scrolled.next());
});
}
/** Cleans up the global scroll listener. */
_removeGlobalListener() {
if (this._globalSubscription) {
this._globalSubscription.unsubscribe();
this._globalSubscription = null;
}
}
};
_ScrollDispatcher.ɵfac = function ScrollDispatcher_Factory(t) {
return new (t || _ScrollDispatcher)(ɵɵinject(NgZone), ɵɵinject(Platform), ɵɵinject(DOCUMENT, 8));
};
_ScrollDispatcher.ɵprov = ɵɵdefineInjectable({
token: _ScrollDispatcher,
factory: _ScrollDispatcher.ɵfac,
providedIn: "root"
});
var ScrollDispatcher = _ScrollDispatcher;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ScrollDispatcher, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: NgZone
}, {
type: Platform
}, {
type: void 0,
decorators: [{
type: Optional
}, {
type: Inject,
args: [DOCUMENT]
}]
}], null);
})();
var _CdkScrollable = class _CdkScrollable {
constructor(elementRef, scrollDispatcher, ngZone, dir) {
this.elementRef = elementRef;
this.scrollDispatcher = scrollDispatcher;
this.ngZone = ngZone;
this.dir = dir;
this._destroyed = new Subject();
this._elementScrolled = new Observable((observer) => this.ngZone.runOutsideAngular(() => fromEvent(this.elementRef.nativeElement, "scroll").pipe(takeUntil(this._destroyed)).subscribe(observer)));
}
ngOnInit() {
this.scrollDispatcher.register(this);
}
ngOnDestroy() {
this.scrollDispatcher.deregister(this);
this._destroyed.next();
this._destroyed.complete();
}
/** Returns observable that emits when a scroll event is fired on the host element. */
elementScrolled() {
return this._elementScrolled;
}
/** Gets the ElementRef for the viewport. */
getElementRef() {
return this.elementRef;
}
/**
* Scrolls to the specified offsets. This is a normalized version of the browser's native scrollTo
* method, since browsers are not consistent about what scrollLeft means in RTL. For this method
* left and right always refer to the left and right side of the scrolling container irrespective
* of the layout direction. start and end refer to left and right in an LTR context and vice-versa
* in an RTL context.
* @param options specified the offsets to scroll to.
*/
scrollTo(options) {
const el = this.elementRef.nativeElement;
const isRtl = this.dir && this.dir.value == "rtl";
if (options.left == null) {
options.left = isRtl ? options.end : options.start;
}
if (options.right == null) {
options.right = isRtl ? options.start : options.end;
}
if (options.bottom != null) {
options.top = el.scrollHeight - el.clientHeight - options.bottom;
}
if (isRtl && getRtlScrollAxisType() != 0) {
if (options.left != null) {
options.right = el.scrollWidth - el.clientWidth - options.left;
}
if (getRtlScrollAxisType() == 2) {
options.left = options.right;
} else if (getRtlScrollAxisType() == 1) {
options.left = options.right ? -options.right : options.right;
}
} else {
if (options.right != null) {
options.left = el.scrollWidth - el.clientWidth - options.right;
}
}
this._applyScrollToOptions(options);
}
_applyScrollToOptions(options) {
const el = this.elementRef.nativeElement;
if (supportsScrollBehavior()) {
el.scrollTo(options);
} else {
if (options.top != null) {
el.scrollTop = options.top;
}
if (options.left != null) {
el.scrollLeft = options.left;
}
}
}
/**
* Measures the scroll offset relative to the specified edge of the viewport. This method can be
* used instead of directly checking scrollLeft or scrollTop, since browsers are not consistent
* about what scrollLeft means in RTL. The values returned by this method are normalized such that
* left and right always refer to the left and right side of the scrolling container irrespective
* of the layout direction. start and end refer to left and right in an LTR context and vice-versa
* in an RTL context.
* @param from The edge to measure from.
*/
measureScrollOffset(from) {
const LEFT = "left";
const RIGHT = "right";
const el = this.elementRef.nativeElement;
if (from == "top") {
return el.scrollTop;
}
if (from == "bottom") {
return el.scrollHeight - el.clientHeight - el.scrollTop;
}
const isRtl = this.dir && this.dir.value == "rtl";
if (from == "start") {
from = isRtl ? RIGHT : LEFT;
} else if (from == "end") {
from = isRtl ? LEFT : RIGHT;
}
if (isRtl && getRtlScrollAxisType() == 2) {
if (from == LEFT) {
return el.scrollWidth - el.clientWidth - el.scrollLeft;
} else {
return el.scrollLeft;
}
} else if (isRtl && getRtlScrollAxisType() == 1) {
if (from == LEFT) {
return el.scrollLeft + el.scrollWidth - el.clientWidth;
} else {
return -el.scrollLeft;
}
} else {
if (from == LEFT) {
return el.scrollLeft;
} else {
return el.scrollWidth - el.clientWidth - el.scrollLeft;
}
}
}
};
_CdkScrollable.ɵfac = function CdkScrollable_Factory(t) {
return new (t || _CdkScrollable)(ɵɵdirectiveInject(ElementRef), ɵɵdirectiveInject(ScrollDispatcher), ɵɵdirectiveInject(NgZone), ɵɵdirectiveInject(Directionality, 8));
};
_CdkScrollable.ɵdir = ɵɵdefineDirective({
type: _CdkScrollable,
selectors: [["", "cdk-scrollable", ""], ["", "cdkScrollable", ""]],
standalone: true
});
var CdkScrollable = _CdkScrollable;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CdkScrollable, [{
type: Directive,
args: [{
selector: "[cdk-scrollable], [cdkScrollable]",
standalone: true
}]
}], () => [{
type: ElementRef
}, {
type: ScrollDispatcher
}, {
type: NgZone
}, {
type: Directionality,
decorators: [{
type: Optional
}]
}], null);
})();
var DEFAULT_RESIZE_TIME = 20;
var _ViewportRuler = class _ViewportRuler {
constructor(_platform, ngZone, document2) {
this._platform = _platform;
this._change = new Subject();
this._changeListener = (event) => {
this._change.next(event);
};
this._document = document2;
ngZone.runOutsideAngular(() => {
if (_platform.isBrowser) {
const window2 = this._getWindow();
window2.addEventListener("resize", this._changeListener);
window2.addEventListener("orientationchange", this._changeListener);
}
this.change().subscribe(() => this._viewportSize = null);
});
}
ngOnDestroy() {
if (this._platform.isBrowser) {
const window2 = this._getWindow();
window2.removeEventListener("resize", this._changeListener);
window2.removeEventListener("orientationchange", this._changeListener);
}
this._change.complete();
}
/** Returns the viewport's width and height. */
getViewportSize() {
if (!this._viewportSize) {
this._updateViewportSize();
}
const output = {
width: this._viewportSize.width,
height: this._viewportSize.height
};
if (!this._platform.isBrowser) {
this._viewportSize = null;
}
return output;
}
/** Gets a ClientRect for the viewport's bounds. */
getViewportRect() {
const scrollPosition = this.getViewportScrollPosition();
const {
width,
height
} = this.getViewportSize();
return {
top: scrollPosition.top,
left: scrollPosition.left,
bottom: scrollPosition.top + height,
right: scrollPosition.left + width,
height,
width
};
}
/** Gets the (top, left) scroll position of the viewport. */
getViewportScrollPosition() {
if (!this._platform.isBrowser) {
return {
top: 0,
left: 0
};
}
const document2 = this._document;
const window2 = this._getWindow();
const documentElement = document2.documentElement;
const documentRect = documentElement.getBoundingClientRect();
const top = -documentRect.top || document2.body.scrollTop || window2.scrollY || documentElement.scrollTop || 0;
const left = -documentRect.left || document2.body.scrollLeft || window2.scrollX || documentElement.scrollLeft || 0;
return {
top,
left
};
}
/**
* Returns a stream that emits whenever the size of the viewport changes.
* This stream emits outside of the Angular zone.
* @param throttleTime Time in milliseconds to throttle the stream.
*/
change(throttleTime = DEFAULT_RESIZE_TIME) {
return throttleTime > 0 ? this._change.pipe(auditTime(throttleTime)) : this._change;
}
/** Use defaultView of injected document if available or fallback to global window reference */
_getWindow() {
return this._document.defaultView || window;
}
/** Updates the cached viewport size. */
_updateViewportSize() {
const window2 = this._getWindow();
this._viewportSize = this._platform.isBrowser ? {
width: window2.innerWidth,
height: window2.innerHeight
} : {
width: 0,
height: 0
};
}
};
_ViewportRuler.ɵfac = function ViewportRuler_Factory(t) {
return new (t || _ViewportRuler)(ɵɵinject(Platform), ɵɵinject(NgZone), ɵɵinject(DOCUMENT, 8));
};
_ViewportRuler.ɵprov = ɵɵdefineInjectable({
token: _ViewportRuler,
factory: _ViewportRuler.ɵfac,
providedIn: "root"
});
var ViewportRuler = _ViewportRuler;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ViewportRuler, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: Platform
}, {
type: NgZone
}, {
type: void 0,
decorators: [{
type: Optional
}, {
type: Inject,
args: [DOCUMENT]
}]
}], null);
})();
var VIRTUAL_SCROLLABLE = new InjectionToken("VIRTUAL_SCROLLABLE");
var _CdkVirtualScrollable = class _CdkVirtualScrollable extends CdkScrollable {
constructor(elementRef, scrollDispatcher, ngZone, dir) {
super(elementRef, scrollDispatcher, ngZone, dir);
}
/**
* Measure the viewport size for the provided orientation.
*
* @param orientation The orientation to measure the size from.
*/
measureViewportSize(orientation) {
const viewportEl = this.elementRef.nativeElement;
return orientation === "horizontal" ? viewportEl.clientWidth : viewportEl.clientHeight;
}
};
_CdkVirtualScrollable.ɵfac = function CdkVirtualScrollable_Factory(t) {
return new (t || _CdkVirtualScrollable)(ɵɵdirectiveInject(ElementRef), ɵɵdirectiveInject(ScrollDispatcher), ɵɵdirectiveInject(NgZone), ɵɵdirectiveInject(Directionality, 8));
};
_CdkVirtualScrollable.ɵdir = ɵɵdefineDirective({
type: _CdkVirtualScrollable,
features: [ɵɵInheritDefinitionFeature]
});
var CdkVirtualScrollable = _CdkVirtualScrollable;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CdkVirtualScrollable, [{
type: Directive
}], () => [{
type: ElementRef
}, {
type: ScrollDispatcher
}, {
type: NgZone
}, {
type: Directionality,
decorators: [{
type: Optional
}]
}], null);
})();
function rangesEqual(r1, r2) {
return r1.start == r2.start && r1.end == r2.end;
}
var SCROLL_SCHEDULER = typeof requestAnimationFrame !== "undefined" ? animationFrameScheduler : asapScheduler;
var _CdkVirtualScrollViewport = class _CdkVirtualScrollViewport extends CdkVirtualScrollable {
/** The direction the viewport scrolls. */
get orientation() {
return this._orientation;
}
set orientation(orientation) {
if (this._orientation !== orientation) {
this._orientation = orientation;
this._calculateSpacerSize();
}
}
constructor(elementRef, _changeDetectorRef, ngZone, _scrollStrategy, dir, scrollDispatcher, viewportRuler, scrollable) {
super(elementRef, scrollDispatcher, ngZone, dir);
this.elementRef = elementRef;
this._changeDetectorRef = _changeDetectorRef;
this._scrollStrategy = _scrollStrategy;
this.scrollable = scrollable;
this._platform = inject(Platform);
this._detachedSubject = new Subject();
this._renderedRangeSubject = new Subject();
this._orientation = "vertical";
this.appendOnly = false;
this.scrolledIndexChange = new Observable((observer) => this._scrollStrategy.scrolledIndexChange.subscribe((index) => Promise.resolve().then(() => this.ngZone.run(() => observer.next(index)))));
this.renderedRangeStream = this._renderedRangeSubject;
this._totalContentSize = 0;
this._totalContentWidth = "";
this._totalContentHeight = "";
this._renderedRange = {
start: 0,
end: 0
};
this._dataLength = 0;
this._viewportSize = 0;
this._renderedContentOffset = 0;
this._renderedContentOffsetNeedsRewrite = false;
this._isChangeDetectionPending = false;
this._runAfterChangeDetection = [];
this._viewportChanges = Subscription.EMPTY;
if (!_scrollStrategy && (typeof ngDevMode === "undefined" || ngDevMode)) {
throw Error('Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set.');
}
this._viewportChanges = viewportRuler.change().subscribe(() => {
this.checkViewportSize();
});
if (!this.scrollable) {
this.elementRef.nativeElement.classList.add("cdk-virtual-scrollable");
this.scrollable = this;
}
}
ngOnInit() {
if (!this._platform.isBrowser) {
return;
}
if (this.scrollable === this) {
super.ngOnInit();
}
this.ngZone.runOutsideAngular(() => Promise.resolve().then(() => {
this._measureViewportSize();
this._scrollStrategy.attach(this);
this.scrollable.elementScrolled().pipe(
// Start off with a fake scroll event so we properly detect our initial position.
startWith(null),
// Collect multiple events into one until the next animation frame. This way if
// there are multiple scroll events in the same frame we only need to recheck
// our layout once.
auditTime(0, SCROLL_SCHEDULER),
// Usually `elementScrolled` is completed when the scrollable is destroyed, but
// that may not be the case if a `CdkVirtualScrollableElement` is used so we have
// to unsubscribe here just in case.
takeUntil(this._destroyed)
).subscribe(() => this._scrollStrategy.onContentScrolled());
this._markChangeDetectionNeeded();
}));
}
ngOnDestroy() {
this.detach();
this._scrollStrategy.detach();
this._renderedRangeSubject.complete();
this._detachedSubject.complete();
this._viewportChanges.unsubscribe();
super.ngOnDestroy();
}
/** Attaches a `CdkVirtualScrollRepeater` to this viewport. */
attach(forOf) {
if (this._forOf && (typeof ngDevMode === "undefined" || ngDevMode)) {
throw Error("CdkVirtualScrollViewport is already attached.");
}
this.ngZone.runOutsideAngular(() => {
this._forOf = forOf;
this._forOf.dataStream.pipe(takeUntil(this._detachedSubject)).subscribe((data) => {
const newLength = data.length;
if (newLength !== this._dataLength) {
this._dataLength = newLength;
this._scrollStrategy.onDataLengthChanged();
}
this._doChangeDetection();
});
});
}
/** Detaches the current `CdkVirtualForOf`. */
detach() {
this._forOf = null;
this._detachedSubject.next();
}
/** Gets the length of the data bound to this viewport (in number of items). */
getDataLength() {
return this._dataLength;
}
/** Gets the size of the viewport (in pixels). */
getViewportSize() {
return this._viewportSize;
}
// TODO(mmalerba): This is technically out of sync with what's really rendered until a render
// cycle happens. I'm being careful to only call it after the render cycle is complete and before
// setting it to something else, but its error prone and should probably be split into
// `pendingRange` and `renderedRange`, the latter reflecting whats actually in the DOM.
/** Get the current rendered range of items. */
getRenderedRange() {
return this._renderedRange;
}
measureBoundingClientRectWithScrollOffset(from) {
return this.getElementRef().nativeElement.getBoundingClientRect()[from];
}
/**
* Sets the total size of all content (in pixels), including content that is not currently
* rendered.
*/
setTotalContentSize(size) {
if (this._totalContentSize !== size) {
this._totalContentSize = size;
this._calculateSpacerSize();
this._markChangeDetectionNeeded();
}
}
/** Sets the currently rendered range of indices. */
setRenderedRange(range) {
if (!rangesEqual(this._renderedRange, range)) {
if (this.appendOnly) {
range = {
start: 0,
end: Math.max(this._renderedRange.end, range.end)
};
}
this._renderedRangeSubject.next(this._renderedRange = range);
this._markChangeDetectionNeeded(() => this._scrollStrategy.onContentRendered());
}
}
/**
* Gets the offset from the start of the viewport to the start of the rendered data (in pixels).
*/
getOffsetToRenderedContentStart() {
return this._renderedContentOffsetNeedsRewrite ? null : this._renderedContentOffset;
}
/**
* Sets the offset from the start of the viewport to either the start or end of the rendered data
* (in pixels).
*/
setRenderedContentOffset(offset, to = "to-start") {
offset = this.appendOnly && to === "to-start" ? 0 : offset;
const isRtl = this.dir && this.dir.value == "rtl";
const isHorizontal = this.orientation == "horizontal";
const axis = isHorizontal ? "X" : "Y";
const axisDirection = isHorizontal && isRtl ? -1 : 1;
let transform = `translate${axis}(${Number(axisDirection * offset)}px)`;
this._renderedContentOffset = offset;
if (to === "to-end") {
transform += ` translate${axis}(-100%)`;
this._renderedContentOffsetNeedsRewrite = true;
}
if (this._renderedContentTransform != transform) {
this._renderedContentTransform = transform;
this._markChangeDetectionNeeded(() => {
if (this._renderedContentOffsetNeedsRewrite) {
this._renderedContentOffset -= this.measureRenderedContentSize();
this._renderedContentOffsetNeedsRewrite = false;
this.setRenderedContentOffset(this._renderedContentOffset);
} else {
this._scrollStrategy.onRenderedOffsetChanged();
}
});
}
}
/**
* Scrolls to the given offset from the start of the viewport. Please note that this is not always
* the same as setting `scrollTop` or `scrollLeft`. In a horizontal viewport with right-to-left
* direction, this would be the equivalent of setting a fictional `scrollRight` property.
* @param offset The offset to scroll to.
* @param behavior The ScrollBehavior to use when scrolling. Default is behavior is `auto`.
*/
scrollToOffset(offset, behavior = "auto") {
const options = {
behavior
};
if (this.orientation === "horizontal") {
options.start = offset;
} else {
options.top = offset;
}
this.scrollable.scrollTo(options);
}
/**
* Scrolls to the offset for the given index.
* @param index The index of the element to scroll to.
* @param behavior The ScrollBehavior to use when scrolling. Default is behavior is `auto`.
*/
scrollToIndex(index, behavior = "auto") {
this._scrollStrategy.scrollToIndex(index, behavior);
}
/**
* Gets the current scroll offset from the start of the scrollable (in pixels).
* @param from The edge to measure the offset from. Defaults to 'top' in vertical mode and 'start'
* in horizontal mode.
*/
measureScrollOffset(from) {
let measureScrollOffset;
if (this.scrollable == this) {
measureScrollOffset = (_from) => super.measureScrollOffset(_from);
} else {
measureScrollOffset = (_from) => this.scrollable.measureScrollOffset(_from);
}
return Math.max(0, measureScrollOffset(from ?? (this.orientation === "horizontal" ? "start" : "top")) - this.measureViewportOffset());
}
/**
* Measures the offset of the viewport from the scrolling container
* @param from The edge to measure from.
*/
measureViewportOffset(from) {
let fromRect;
const LEFT = "left";
const RIGHT = "right";
const isRtl = this.dir?.value == "rtl";
if (from == "start") {
fromRect = isRtl ? RIGHT : LEFT;
} else if (from == "end") {
fromRect = isRtl ? LEFT : RIGHT;
} else if (from) {
fromRect = from;
} else {
fromRect = this.orientation === "horizontal" ? "left" : "top";
}
const scrollerClientRect = this.scrollable.measureBoundingClientRectWithScrollOffset(fromRect);
const viewportClientRect = this.elementRef.nativeElement.getBoundingClientRect()[fromRect];
return viewportClientRect - scrollerClientRect;
}
/** Measure the combined size of all of the rendered items. */
measureRenderedContentSize() {
const contentEl = this._contentWrapper.nativeElement;
return this.orientation === "horizontal" ? contentEl.offsetWidth : contentEl.offsetHeight;
}
/**
* Measure the total combined size of the given range. Throws if the range includes items that are
* not rendered.
*/
measureRangeSize(range) {
if (!this._forOf) {
return 0;
}
return this._forOf.measureRangeSize(range, this.orientation);
}
/** Update the viewport dimensions and re-render. */
checkViewportSize() {
this._measureViewportSize();
this._scrollStrategy.onDataLengthChanged();
}
/** Measure the viewport size. */
_measureViewportSize() {
this._viewportSize = this.scrollable.measureViewportSize(this.orientation);
}
/** Queue up change detection to run. */
_markChangeDetectionNeeded(runAfter) {
if (runAfter) {
this._runAfterChangeDetection.push(runAfter);
}
if (!this._isChangeDetectionPending) {
this._isChangeDetectionPending = true;
this.ngZone.runOutsideAngular(() => Promise.resolve().then(() => {
this._doChangeDetection();
}));
}
}
/** Run change detection. */
_doChangeDetection() {
this._isChangeDetectionPending = false;
this._contentWrapper.nativeElement.style.transform = this._renderedContentTransform;
this.ngZone.run(() => this._changeDetectorRef.markForCheck());
const runAfterChangeDetection = this._runAfterChangeDetection;
this._runAfterChangeDetection = [];
for (const fn of runAfterChangeDetection) {
fn();
}
}
/** Calculates the `style.width` and `style.height` for the spacer element. */
_calculateSpacerSize() {
this._totalContentHeight = this.orientation === "horizontal" ? "" : `${this._totalContentSize}px`;
this._totalContentWidth = this.orientation === "horizontal" ? `${this._totalContentSize}px` : "";
}
};
_CdkVirtualScrollViewport.ɵfac = function CdkVirtualScrollViewport_Factory(t) {
return new (t || _CdkVirtualScrollViewport)(ɵɵdirectiveInject(ElementRef), ɵɵdirectiveInject(ChangeDetectorRef), ɵɵdirectiveInject(NgZone), ɵɵdirectiveInject(VIRTUAL_SCROLL_STRATEGY, 8), ɵɵdirectiveInject(Directionality, 8), ɵɵdirectiveInject(ScrollDispatcher), ɵɵdirectiveInject(ViewportRuler), ɵɵdirectiveInject(VIRTUAL_SCROLLABLE, 8));
};
_CdkVirtualScrollViewport.ɵcmp = ɵɵdefineComponent({
type: _CdkVirtualScrollViewport,
selectors: [["cdk-virtual-scroll-viewport"]],
viewQuery: function CdkVirtualScrollViewport_Query(rf, ctx) {
if (rf & 1) {
ɵɵviewQuery(_c0, 7);
}
if (rf & 2) {
let _t;
ɵɵqueryRefresh(_t = ɵɵloadQuery()) && (ctx._contentWrapper = _t.first);
}
},
hostAttrs: [1, "cdk-virtual-scroll-viewport"],
hostVars: 4,
hostBindings: function CdkVirtualScrollViewport_HostBindings(rf, ctx) {
if (rf & 2) {
ɵɵclassProp("cdk-virtual-scroll-orientation-horizontal", ctx.orientation === "horizontal")("cdk-virtual-scroll-orientation-vertical", ctx.orientation !== "horizontal");
}
},
inputs: {
orientation: "orientation",
appendOnly: ["appendOnly", "appendOnly", booleanAttribute]
},
outputs: {
scrolledIndexChange: "scrolledIndexChange"
},
standalone: true,
features: [ɵɵProvidersFeature([{
provide: CdkScrollable,
useFactory: (virtualScrollable, viewport) => virtualScrollable || viewport,
deps: [[new Optional(), new Inject(VIRTUAL_SCROLLABLE)], _CdkVirtualScrollViewport]
}]), ɵɵInputTransformsFeature, ɵɵInheritDefinitionFeature, ɵɵStandaloneFeature],
ngContentSelectors: _c1,
decls: 4,
vars: 4,
consts: [[1, "cdk-virtual-scroll-content-wrapper"], ["contentWrapper", ""], [1, "cdk-virtual-scroll-spacer"]],
template: function CdkVirtualScrollViewport_Template(rf, ctx) {
if (rf & 1) {
ɵɵprojectionDef();
ɵɵelementStart(0, "div", 0, 1);
ɵɵprojection(2);
ɵɵelementEnd();
ɵɵelement(3, "div", 2);
}
if (rf & 2) {
ɵɵadvance(3);
ɵɵstyleProp("width", ctx._totalContentWidth)("height", ctx._totalContentHeight);
}
},
styles: ["cdk-virtual-scroll-viewport{display:block;position:relative;transform:translateZ(0)}.cdk-virtual-scrollable{overflow:auto;will-change:scroll-position;contain:strict;-webkit-overflow-scrolling:touch}.cdk-virtual-scroll-content-wrapper{position:absolute;top:0;left:0;contain:content}[dir=rtl] .cdk-virtual-scroll-content-wrapper{right:0;left:auto}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper{min-height:100%}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-left:0;padding-right:0;margin-left:0;margin-right:0;border-left-width:0;border-right-width:0;outline:none}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper{min-width:100%}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;border-top-width:0;border-bottom-width:0;outline:none}.cdk-virtual-scroll-spacer{height:1px;transform-origin:0 0;flex:0 0 auto}[dir=rtl] .cdk-virtual-scroll-spacer{transform-origin:100% 0}"],
encapsulation: 2,
changeDetection: 0
});
var CdkVirtualScrollViewport = _CdkVirtualScrollViewport;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CdkVirtualScrollViewport, [{
type: Component,
args: [{
selector: "cdk-virtual-scroll-viewport",
host: {
"class": "cdk-virtual-scroll-viewport",
"[class.cdk-virtual-scroll-orientation-horizontal]": 'orientation === "horizontal"',
"[class.cdk-virtual-scroll-orientation-vertical]": 'orientation !== "horizontal"'
},
encapsulation: ViewEncapsulation$1.None,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
providers: [{
provide: CdkScrollable,
useFactory: (virtualScrollable, viewport) => virtualScrollable || viewport,
deps: [[new Optional(), new Inject(VIRTUAL_SCROLLABLE)], CdkVirtualScrollViewport]
}],
template: '\n
\n \n
\n\n\n',
styles: ["cdk-virtual-scroll-viewport{display:block;position:relative;transform:translateZ(0)}.cdk-virtual-scrollable{overflow:auto;will-change:scroll-position;contain:strict;-webkit-overflow-scrolling:touch}.cdk-virtual-scroll-content-wrapper{position:absolute;top:0;left:0;contain:content}[dir=rtl] .cdk-virtual-scroll-content-wrapper{right:0;left:auto}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper{min-height:100%}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-left:0;padding-right:0;margin-left:0;margin-right:0;border-left-width:0;border-right-width:0;outline:none}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper{min-width:100%}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;border-top-width:0;border-bottom-width:0;outline:none}.cdk-virtual-scroll-spacer{height:1px;transform-origin:0 0;flex:0 0 auto}[dir=rtl] .cdk-virtual-scroll-spacer{transform-origin:100% 0}"]
}]
}], () => [{
type: ElementRef
}, {
type: ChangeDetectorRef
}, {
type: NgZone
}, {
type: void 0,
decorators: [{
type: Optional
}, {
type: Inject,
args: [VIRTUAL_SCROLL_STRATEGY]
}]
}, {
type: Directionality,
decorators: [{
type: Optional
}]
}, {
type: ScrollDispatcher
}, {
type: ViewportRuler
}, {
type: CdkVirtualScrollable,
decorators: [{
type: Optional
}, {
type: Inject,
args: [VIRTUAL_SCROLLABLE]
}]
}], {
orientation: [{
type: Input
}],
appendOnly: [{
type: Input,
args: [{
transform: booleanAttribute
}]
}],
scrolledIndexChange: [{
type: Output
}],
_contentWrapper: [{
type: ViewChild,
args: ["contentWrapper", {
static: true
}]
}]
});
})();
function getOffset(orientation, direction, node) {
const el = node;
if (!el.getBoundingClientRect) {
return 0;
}
const rect = el.getBoundingClientRect();
if (orientation === "horizontal") {
return direction === "start" ? rect.left : rect.right;
}
return direction === "start" ? rect.top : rect.bottom;
}
var _CdkVirtualForOf = class _CdkVirtualForOf {
/** The DataSource to display. */
get cdkVirtualForOf() {
return this._cdkVirtualForOf;
}
set cdkVirtualForOf(value) {
this._cdkVirtualForOf = value;
if (isDataSource(value)) {
this._dataSourceChanges.next(value);
} else {
this._dataSourceChanges.next(new ArrayDataSource(isObservable(value) ? value : Array.from(value || [])));
}
}
/**
* The `TrackByFunction` to use for tracking changes. The `TrackByFunction` takes the index and
* the item and produces a value to be used as the item's identity when tracking changes.
*/
get cdkVirtualForTrackBy() {
return this._cdkVirtualForTrackBy;
}
set cdkVirtualForTrackBy(fn) {
this._needsUpdate = true;
this._cdkVirtualForTrackBy = fn ? (index, item) => fn(index + (this._renderedRange ? this._renderedRange.start : 0), item) : void 0;
}
/** The template used to stamp out new elements. */
set cdkVirtualForTemplate(value) {
if (value) {
this._needsUpdate = true;
this._template = value;
}
}
/**
* The size of the cache used to store templates that are not being used for re-use later.
* Setting the cache size to `0` will disable caching. Defaults to 20 templates.
*/
get cdkVirtualForTemplateCacheSize() {
return this._viewRepeater.viewCacheSize;
}
set cdkVirtualForTemplateCacheSize(size) {
this._viewRepeater.viewCacheSize = coerceNumberProperty(size);
}
constructor(_viewContainerRef, _template, _differs, _viewRepeater, _viewport, ngZone) {
this._viewContainerRef = _viewContainerRef;
this._template = _template;
this._differs = _differs;
this._viewRepeater = _viewRepeater;
this._viewport = _viewport;
this.viewChange = new Subject();
this._dataSourceChanges = new Subject();
this.dataStream = this._dataSourceChanges.pipe(
// Start off with null `DataSource`.
startWith(null),
// Bundle up the previous and current data sources so we can work with both.
pairwise(),
// Use `_changeDataSource` to disconnect from the previous data source and connect to the
// new one, passing back a stream of data changes which we run through `switchMap` to give
// us a data stream that emits the latest data from whatever the current `DataSource` is.
switchMap(([prev, cur]) => this._changeDataSource(prev, cur)),
// Replay the last emitted data when someone subscribes.
shareReplay(1)
);
this._differ = null;
this._needsUpdate = false;
this._destroyed = new Subject();
this.dataStream.subscribe((data) => {
this._data = data;
this._onRenderedDataChange();
});
this._viewport.renderedRangeStream.pipe(takeUntil(this._destroyed)).subscribe((range) => {
this._renderedRange = range;
if (this.viewChange.observers.length) {
ngZone.run(() => this.viewChange.next(this._renderedRange));
}
this._onRenderedDataChange();
});
this._viewport.attach(this);
}
/**
* Measures the combined size (width for horizontal orientation, height for vertical) of all items
* in the specified range. Throws an error if the range includes items that are not currently
* rendered.
*/
measureRangeSize(range, orientation) {
if (range.start >= range.end) {
return 0;
}
if ((range.start < this._renderedRange.start || range.end > this._renderedRange.end) && (typeof ngDevMode === "undefined" || ngDevMode)) {
throw Error(`Error: attempted to measure an item that isn't rendered.`);
}
const renderedStartIndex = range.start - this._renderedRange.start;
const rangeLen = range.end - range.start;
let firstNode;
let lastNode;
for (let i = 0; i < rangeLen; i++) {
const view = this._viewContainerRef.get(i + renderedStartIndex);
if (view && view.rootNodes.length) {
firstNode = lastNode = view.rootNodes[0];
break;
}
}
for (let i = rangeLen - 1; i > -1; i--) {
const view = this._viewContainerRef.get(i + renderedStartIndex);
if (view && view.rootNodes.length) {
lastNode = view.rootNodes[view.rootNodes.length - 1];
break;
}
}
return firstNode && lastNode ? getOffset(orientation, "end", lastNode) - getOffset(orientation, "start", firstNode) : 0;
}
ngDoCheck() {
if (this._differ && this._needsUpdate) {
const changes = this._differ.diff(this._renderedItems);
if (!changes) {
this._updateContext();
} else {
this._applyChanges(changes);
}
this._needsUpdate = false;
}
}
ngOnDestroy() {
this._viewport.detach();
this._dataSourceChanges.next(void 0);
this._dataSourceChanges.complete();
this.viewChange.complete();
this._destroyed.next();
this._destroyed.complete();
this._viewRepeater.detach();
}
/** React to scroll state changes in the viewport. */
_onRenderedDataChange() {
if (!this._renderedRange) {
return;
}
this._renderedItems = this._data.slice(this._renderedRange.start, this._renderedRange.end);
if (!this._differ) {
this._differ = this._differs.find(this._renderedItems).create((index, item) => {
return this.cdkVirtualForTrackBy ? this.cdkVirtualForTrackBy(index, item) : item;
});
}
this._needsUpdate = true;
}
/** Swap out one `DataSource` for another. */
_changeDataSource(oldDs, newDs) {
if (oldDs) {
oldDs.disconnect(this);
}
this._needsUpdate = true;
return newDs ? newDs.connect(this) : of();
}
/** Update the `CdkVirtualForOfContext` for all views. */
_updateContext() {
const count = this._data.length;
let i = this._viewContainerRef.length;
while (i--) {
const view = this._viewContainerRef.get(i);
view.context.index = this._renderedRange.start + i;
view.context.count = count;
this._updateComputedContextProperties(view.context);
view.detectChanges();
}
}
/** Apply changes to the DOM. */
_applyChanges(changes) {
this._viewRepeater.applyChanges(changes, this._viewContainerRef, (record, _adjustedPreviousIndex, currentIndex) => this._getEmbeddedViewArgs(record, currentIndex), (record) => record.item);
changes.forEachIdentityChange((record) => {
const view = this._viewContainerRef.get(record.currentIndex);
view.context.$implicit = record.item;
});
const count = this._data.length;
let i = this._viewContainerRef.length;
while (i--) {
const view = this._viewContainerRef.get(i);
view.context.index = this._renderedRange.start + i;
view.context.count = count;
this._updateComputedContextProperties(view.context);
}
}
/** Update the computed properties on the `CdkVirtualForOfContext`. */
_updateComputedContextProperties(context) {
context.first = context.index === 0;
context.last = context.index === context.count - 1;
context.even = context.index % 2 === 0;
context.odd = !context.even;
}
_getEmbeddedViewArgs(record, index) {
return {
templateRef: this._template,
context: {
$implicit: record.item,
// It's guaranteed that the iterable is not "undefined" or "null" because we only
// generate views for elements if the "cdkVirtualForOf" iterable has elements.
cdkVirtualForOf: this._cdkVirtualForOf,
index: -1,
count: -1,
first: false,
last: false,
odd: false,
even: false
},
index
};
}
};
_CdkVirtualForOf.ɵfac = function CdkVirtualForOf_Factory(t) {
return new (t || _CdkVirtualForOf)(ɵɵdirectiveInject(ViewContainerRef), ɵɵdirectiveInject(TemplateRef), ɵɵdirectiveInject(IterableDiffers), ɵɵdirectiveInject(_VIEW_REPEATER_STRATEGY), ɵɵdirectiveInject(CdkVirtualScrollViewport, 4), ɵɵdirectiveInject(NgZone));
};
_CdkVirtualForOf.ɵdir = ɵɵdefineDirective({
type: _CdkVirtualForOf,
selectors: [["", "cdkVirtualFor", "", "cdkVirtualForOf", ""]],
inputs: {
cdkVirtualForOf: "cdkVirtualForOf",
cdkVirtualForTrackBy: "cdkVirtualForTrackBy",
cdkVirtualForTemplate: "cdkVirtualForTemplate",
cdkVirtualForTemplateCacheSize: "cdkVirtualForTemplateCacheSize"
},
standalone: true,
features: [ɵɵProvidersFeature([{
provide: _VIEW_REPEATER_STRATEGY,
useClass: _RecycleViewRepeaterStrategy
}])]
});
var CdkVirtualForOf = _CdkVirtualForOf;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CdkVirtualForOf, [{
type: Directive,
args: [{
selector: "[cdkVirtualFor][cdkVirtualForOf]",
providers: [{
provide: _VIEW_REPEATER_STRATEGY,
useClass: _RecycleViewRepeaterStrategy
}],
standalone: true
}]
}], () => [{
type: ViewContainerRef
}, {
type: TemplateRef
}, {
type: IterableDiffers
}, {
type: _RecycleViewRepeaterStrategy,
decorators: [{
type: Inject,
args: [_VIEW_REPEATER_STRATEGY]
}]
}, {
type: CdkVirtualScrollViewport,
decorators: [{
type: SkipSelf
}]
}, {
type: NgZone
}], {
cdkVirtualForOf: [{
type: Input
}],
cdkVirtualForTrackBy: [{
type: Input
}],
cdkVirtualForTemplate: [{
type: Input
}],
cdkVirtualForTemplateCacheSize: [{
type: Input
}]
});
})();
var _CdkVirtualScrollableElement = class _CdkVirtualScrollableElement extends CdkVirtualScrollable {
constructor(elementRef, scrollDispatcher, ngZone, dir) {
super(elementRef, scrollDispatcher, ngZone, dir);
}
measureBoundingClientRectWithScrollOffset(from) {
return this.getElementRef().nativeElement.getBoundingClientRect()[from] - this.measureScrollOffset(from);
}
};
_CdkVirtualScrollableElement.ɵfac = function CdkVirtualScrollableElement_Factory(t) {
return new (t || _CdkVirtualScrollableElement)(ɵɵdirectiveInject(ElementRef), ɵɵdirectiveInject(ScrollDispatcher), ɵɵdirectiveInject(NgZone), ɵɵdirectiveInject(Directionality, 8));
};
_CdkVirtualScrollableElement.ɵdir = ɵɵdefineDirective({
type: _CdkVirtualScrollableElement,
selectors: [["", "cdkVirtualScrollingElement", ""]],
hostAttrs: [1, "cdk-virtual-scrollable"],
standalone: true,
features: [ɵɵProvidersFeature([{
provide: VIRTUAL_SCROLLABLE,
useExisting: _CdkVirtualScrollableElement
}]), ɵɵInheritDefinitionFeature]
});
var CdkVirtualScrollableElement = _CdkVirtualScrollableElement;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CdkVirtualScrollableElement, [{
type: Directive,
args: [{
selector: "[cdkVirtualScrollingElement]",
providers: [{
provide: VIRTUAL_SCROLLABLE,
useExisting: CdkVirtualScrollableElement
}],
standalone: true,
host: {
"class": "cdk-virtual-scrollable"
}
}]
}], () => [{
type: ElementRef
}, {
type: ScrollDispatcher
}, {
type: NgZone
}, {
type: Directionality,
decorators: [{
type: Optional
}]
}], null);
})();
var _CdkVirtualScrollableWindow = class _CdkVirtualScrollableWindow extends CdkVirtualScrollable {
constructor(scrollDispatcher, ngZone, dir) {
super(new ElementRef(document.documentElement), scrollDispatcher, ngZone, dir);
this._elementScrolled = new Observable((observer) => this.ngZone.runOutsideAngular(() => fromEvent(document, "scroll").pipe(takeUntil(this._destroyed)).subscribe(observer)));
}
measureBoundingClientRectWithScrollOffset(from) {
return this.getElementRef().nativeElement.getBoundingClientRect()[from];
}
};
_CdkVirtualScrollableWindow.ɵfac = function CdkVirtualScrollableWindow_Factory(t) {
return new (t || _CdkVirtualScrollableWindow)(ɵɵdirectiveInject(ScrollDispatcher), ɵɵdirectiveInject(NgZone), ɵɵdirectiveInject(Directionality, 8));
};
_CdkVirtualScrollableWindow.ɵdir = ɵɵdefineDirective({
type: _CdkVirtualScrollableWindow,
selectors: [["cdk-virtual-scroll-viewport", "scrollWindow", ""]],
standalone: true,
features: [ɵɵProvidersFeature([{
provide: VIRTUAL_SCROLLABLE,
useExisting: _CdkVirtualScrollableWindow
}]), ɵɵInheritDefinitionFeature]
});
var CdkVirtualScrollableWindow = _CdkVirtualScrollableWindow;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CdkVirtualScrollableWindow, [{
type: Directive,
args: [{
selector: "cdk-virtual-scroll-viewport[scrollWindow]",
providers: [{
provide: VIRTUAL_SCROLLABLE,
useExisting: CdkVirtualScrollableWindow
}],
standalone: true
}]
}], () => [{
type: ScrollDispatcher
}, {
type: NgZone
}, {
type: Directionality,
decorators: [{
type: Optional
}]
}], null);
})();
var _CdkScrollableModule = class _CdkScrollableModule {
};
_CdkScrollableModule.ɵfac = function CdkScrollableModule_Factory(t) {
return new (t || _CdkScrollableModule)();
};
_CdkScrollableModule.ɵmod = ɵɵdefineNgModule({
type: _CdkScrollableModule,
imports: [CdkScrollable],
exports: [CdkScrollable]
});
_CdkScrollableModule.ɵinj = ɵɵdefineInjector({});
var CdkScrollableModule = _CdkScrollableModule;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CdkScrollableModule, [{
type: NgModule,
args: [{
exports: [CdkScrollable],
imports: [CdkScrollable]
}]
}], null, null);
})();
var _ScrollingModule = class _ScrollingModule {
};
_ScrollingModule.ɵfac = function ScrollingModule_Factory(t) {
return new (t || _ScrollingModule)();
};
_ScrollingModule.ɵmod = ɵɵdefineNgModule({
type: _ScrollingModule,
imports: [BidiModule, CdkScrollableModule, CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollableWindow, CdkVirtualScrollableElement],
exports: [BidiModule, CdkScrollableModule, CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport, CdkVirtualScrollableWindow, CdkVirtualScrollableElement]
});
_ScrollingModule.ɵinj = ɵɵdefineInjector({
imports: [BidiModule, CdkScrollableModule, BidiModule, CdkScrollableModule]
});
var ScrollingModule = _ScrollingModule;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ScrollingModule, [{
type: NgModule,
args: [{
imports: [BidiModule, CdkScrollableModule, CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollableWindow, CdkVirtualScrollableElement],
exports: [BidiModule, CdkScrollableModule, CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport, CdkVirtualScrollableWindow, CdkVirtualScrollableElement]
}]
}], null, null);
})();
// node_modules/@angular/cdk/fesm2022/portal.mjs
function throwNullPortalError() {
throw Error("Must provide a portal to attach");
}
function throwPortalAlreadyAttachedError() {
throw Error("Host already has a portal attached");
}
function throwPortalOutletAlreadyDisposedError() {
throw Error("This PortalOutlet has already been disposed");
}
function throwUnknownPortalTypeError() {
throw Error("Attempting to attach an unknown Portal type. BasePortalOutlet accepts either a ComponentPortal or a TemplatePortal.");
}
function throwNullPortalOutletError() {
throw Error("Attempting to attach a portal to a null PortalOutlet");
}
function throwNoPortalAttachedError() {
throw Error("Attempting to detach a portal that is not attached to a host");
}
var Portal = class {
/** Attach this portal to a host. */
attach(host) {
if (typeof ngDevMode === "undefined" || ngDevMode) {
if (host == null) {
throwNullPortalOutletError();
}
if (host.hasAttached()) {
throwPortalAlreadyAttachedError();
}
}
this._attachedHost = host;
return host.attach(this);
}
/** Detach this portal from its host */
detach() {
let host = this._attachedHost;
if (host != null) {
this._attachedHost = null;
host.detach();
} else if (typeof ngDevMode === "undefined" || ngDevMode) {
throwNoPortalAttachedError();
}
}
/** Whether this portal is attached to a host. */
get isAttached() {
return this._attachedHost != null;
}
/**
* Sets the PortalOutlet reference without performing `attach()`. This is used directly by
* the PortalOutlet when it is performing an `attach()` or `detach()`.
*/
setAttachedHost(host) {
this._attachedHost = host;
}
};
var ComponentPortal = class extends Portal {
constructor(component, viewContainerRef, injector, componentFactoryResolver, projectableNodes) {
super();
this.component = component;
this.viewContainerRef = viewContainerRef;
this.injector = injector;
this.componentFactoryResolver = componentFactoryResolver;
this.projectableNodes = projectableNodes;
}
};
var TemplatePortal = class extends Portal {
constructor(templateRef, viewContainerRef, context, injector) {
super();
this.templateRef = templateRef;
this.viewContainerRef = viewContainerRef;
this.context = context;
this.injector = injector;
}
get origin() {
return this.templateRef.elementRef;
}
/**
* Attach the portal to the provided `PortalOutlet`.
* When a context is provided it will override the `context` property of the `TemplatePortal`
* instance.
*/
attach(host, context = this.context) {
this.context = context;
return super.attach(host);
}
detach() {
this.context = void 0;
return super.detach();
}
};
var DomPortal = class extends Portal {
constructor(element) {
super();
this.element = element instanceof ElementRef ? element.nativeElement : element;
}
};
var BasePortalOutlet = class {
constructor() {
this._isDisposed = false;
this.attachDomPortal = null;
}
/** Whether this host has an attached portal. */
hasAttached() {
return !!this._attachedPortal;
}
/** Attaches a portal. */
attach(portal) {
if (typeof ngDevMode === "undefined" || ngDevMode) {
if (!portal) {
throwNullPortalError();
}
if (this.hasAttached()) {
throwPortalAlreadyAttachedError();
}
if (this._isDisposed) {
throwPortalOutletAlreadyDisposedError();
}
}
if (portal instanceof ComponentPortal) {
this._attachedPortal = portal;
return this.attachComponentPortal(portal);
} else if (portal instanceof TemplatePortal) {
this._attachedPortal = portal;
return this.attachTemplatePortal(portal);
} else if (this.attachDomPortal && portal instanceof DomPortal) {
this._attachedPortal = portal;
return this.attachDomPortal(portal);
}
if (typeof ngDevMode === "undefined" || ngDevMode) {
throwUnknownPortalTypeError();
}
}
/** Detaches a previously attached portal. */
detach() {
if (this._attachedPortal) {
this._attachedPortal.setAttachedHost(null);
this._attachedPortal = null;
}
this._invokeDisposeFn();
}
/** Permanently dispose of this portal host. */
dispose() {
if (this.hasAttached()) {
this.detach();
}
this._invokeDisposeFn();
this._isDisposed = true;
}
/** @docs-private */
setDisposeFn(fn) {
this._disposeFn = fn;
}
_invokeDisposeFn() {
if (this._disposeFn) {
this._disposeFn();
this._disposeFn = null;
}
}
};
var DomPortalOutlet = class extends BasePortalOutlet {
/**
* @param outletElement Element into which the content is projected.
* @param _componentFactoryResolver Used to resolve the component factory.
* Only required when attaching component portals.
* @param _appRef Reference to the application. Only used in component portals when there
* is no `ViewContainerRef` available.
* @param _defaultInjector Injector to use as a fallback when the portal being attached doesn't
* have one. Only used for component portals.
* @param _document Reference to the document. Used when attaching a DOM portal. Will eventually
* become a required parameter.
*/
constructor(outletElement, _componentFactoryResolver, _appRef, _defaultInjector, _document) {
super();
this.outletElement = outletElement;
this._componentFactoryResolver = _componentFactoryResolver;
this._appRef = _appRef;
this._defaultInjector = _defaultInjector;
this.attachDomPortal = (portal) => {
if (!this._document && (typeof ngDevMode === "undefined" || ngDevMode)) {
throw Error("Cannot attach DOM portal without _document constructor parameter");
}
const element = portal.element;
if (!element.parentNode && (typeof ngDevMode === "undefined" || ngDevMode)) {
throw Error("DOM portal content must be attached to a parent node.");
}
const anchorNode = this._document.createComment("dom-portal");
element.parentNode.insertBefore(anchorNode, element);
this.outletElement.appendChild(element);
this._attachedPortal = portal;
super.setDisposeFn(() => {
if (anchorNode.parentNode) {
anchorNode.parentNode.replaceChild(element, anchorNode);
}
});
};
this._document = _document;
}
/**
* Attach the given ComponentPortal to DOM element using the ComponentFactoryResolver.
* @param portal Portal to be attached
* @returns Reference to the created component.
*/
attachComponentPortal(portal) {
const resolver = portal.componentFactoryResolver || this._componentFactoryResolver;
if ((typeof ngDevMode === "undefined" || ngDevMode) && !resolver) {
throw Error("Cannot attach component portal to outlet without a ComponentFactoryResolver.");
}
const componentFactory = resolver.resolveComponentFactory(portal.component);
let componentRef;
if (portal.viewContainerRef) {
componentRef = portal.viewContainerRef.createComponent(componentFactory, portal.viewContainerRef.length, portal.injector || portal.viewContainerRef.injector, portal.projectableNodes || void 0);
this.setDisposeFn(() => componentRef.destroy());
} else {
if ((typeof ngDevMode === "undefined" || ngDevMode) && !this._appRef) {
throw Error("Cannot attach component portal to outlet without an ApplicationRef.");
}
componentRef = componentFactory.create(portal.injector || this._defaultInjector || Injector.NULL);
this._appRef.attachView(componentRef.hostView);
this.setDisposeFn(() => {
if (this._appRef.viewCount > 0) {
this._appRef.detachView(componentRef.hostView);
}
componentRef.destroy();
});
}
this.outletElement.appendChild(this._getComponentRootNode(componentRef));
this._attachedPortal = portal;
return componentRef;
}
/**
* Attaches a template portal to the DOM as an embedded view.
* @param portal Portal to be attached.
* @returns Reference to the created embedded view.
*/
attachTemplatePortal(portal) {
let viewContainer = portal.viewContainerRef;
let viewRef = viewContainer.createEmbeddedView(portal.templateRef, portal.context, {
injector: portal.injector
});
viewRef.rootNodes.forEach((rootNode) => this.outletElement.appendChild(rootNode));
viewRef.detectChanges();
this.setDisposeFn(() => {
let index = viewContainer.indexOf(viewRef);
if (index !== -1) {
viewContainer.remove(index);
}
});
this._attachedPortal = portal;
return viewRef;
}
/**
* Clears out a portal from the DOM.
*/
dispose() {
super.dispose();
this.outletElement.remove();
}
/** Gets the root HTMLElement for an instantiated component. */
_getComponentRootNode(componentRef) {
return componentRef.hostView.rootNodes[0];
}
};
var _CdkPortal = class _CdkPortal extends TemplatePortal {
constructor(templateRef, viewContainerRef) {
super(templateRef, viewContainerRef);
}
};
_CdkPortal.ɵfac = function CdkPortal_Factory(t) {
return new (t || _CdkPortal)(ɵɵdirectiveInject(TemplateRef), ɵɵdirectiveInject(ViewContainerRef));
};
_CdkPortal.ɵdir = ɵɵdefineDirective({
type: _CdkPortal,
selectors: [["", "cdkPortal", ""]],
exportAs: ["cdkPortal"],
features: [ɵɵInheritDefinitionFeature]
});
var CdkPortal = _CdkPortal;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CdkPortal, [{
type: Directive,
args: [{
selector: "[cdkPortal]",
exportAs: "cdkPortal"
}]
}], () => [{
type: TemplateRef
}, {
type: ViewContainerRef
}], null);
})();
var _TemplatePortalDirective = class _TemplatePortalDirective extends CdkPortal {
};
_TemplatePortalDirective.ɵfac = (() => {
let ɵTemplatePortalDirective_BaseFactory;
return function TemplatePortalDirective_Factory(t) {
return (ɵTemplatePortalDirective_BaseFactory || (ɵTemplatePortalDirective_BaseFactory = ɵɵgetInheritedFactory(_TemplatePortalDirective)))(t || _TemplatePortalDirective);
};
})();
_TemplatePortalDirective.ɵdir = ɵɵdefineDirective({
type: _TemplatePortalDirective,
selectors: [["", "cdk-portal", ""], ["", "portal", ""]],
exportAs: ["cdkPortal"],
features: [ɵɵProvidersFeature([{
provide: CdkPortal,
useExisting: _TemplatePortalDirective
}]), ɵɵInheritDefinitionFeature]
});
var TemplatePortalDirective = _TemplatePortalDirective;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(TemplatePortalDirective, [{
type: Directive,
args: [{
selector: "[cdk-portal], [portal]",
exportAs: "cdkPortal",
providers: [{
provide: CdkPortal,
useExisting: TemplatePortalDirective
}]
}]
}], null, null);
})();
var _CdkPortalOutlet = class _CdkPortalOutlet extends BasePortalOutlet {
constructor(_componentFactoryResolver, _viewContainerRef, _document) {
super();
this._componentFactoryResolver = _componentFactoryResolver;
this._viewContainerRef = _viewContainerRef;
this._isInitialized = false;
this.attached = new EventEmitter();
this.attachDomPortal = (portal) => {
if (!this._document && (typeof ngDevMode === "undefined" || ngDevMode)) {
throw Error("Cannot attach DOM portal without _document constructor parameter");
}
const element = portal.element;
if (!element.parentNode && (typeof ngDevMode === "undefined" || ngDevMode)) {
throw Error("DOM portal content must be attached to a parent node.");
}
const anchorNode = this._document.createComment("dom-portal");
portal.setAttachedHost(this);
element.parentNode.insertBefore(anchorNode, element);
this._getRootNode().appendChild(element);
this._attachedPortal = portal;
super.setDisposeFn(() => {
if (anchorNode.parentNode) {
anchorNode.parentNode.replaceChild(element, anchorNode);
}
});
};
this._document = _document;
}
/** Portal associated with the Portal outlet. */
get portal() {
return this._attachedPortal;
}
set portal(portal) {
if (this.hasAttached() && !portal && !this._isInitialized) {
return;
}
if (this.hasAttached()) {
super.detach();
}
if (portal) {
super.attach(portal);
}
this._attachedPortal = portal || null;
}
/** Component or view reference that is attached to the portal. */
get attachedRef() {
return this._attachedRef;
}
ngOnInit() {
this._isInitialized = true;
}
ngOnDestroy() {
super.dispose();
this._attachedRef = this._attachedPortal = null;
}
/**
* Attach the given ComponentPortal to this PortalOutlet using the ComponentFactoryResolver.
*
* @param portal Portal to be attached to the portal outlet.
* @returns Reference to the created component.
*/
attachComponentPortal(portal) {
portal.setAttachedHost(this);
const viewContainerRef = portal.viewContainerRef != null ? portal.viewContainerRef : this._viewContainerRef;
const resolver = portal.componentFactoryResolver || this._componentFactoryResolver;
const componentFactory = resolver.resolveComponentFactory(portal.component);
const ref = viewContainerRef.createComponent(componentFactory, viewContainerRef.length, portal.injector || viewContainerRef.injector, portal.projectableNodes || void 0);
if (viewContainerRef !== this._viewContainerRef) {
this._getRootNode().appendChild(ref.hostView.rootNodes[0]);
}
super.setDisposeFn(() => ref.destroy());
this._attachedPortal = portal;
this._attachedRef = ref;
this.attached.emit(ref);
return ref;
}
/**
* Attach the given TemplatePortal to this PortalHost as an embedded View.
* @param portal Portal to be attached.
* @returns Reference to the created embedded view.
*/
attachTemplatePortal(portal) {
portal.setAttachedHost(this);
const viewRef = this._viewContainerRef.createEmbeddedView(portal.templateRef, portal.context, {
injector: portal.injector
});
super.setDisposeFn(() => this._viewContainerRef.clear());
this._attachedPortal = portal;
this._attachedRef = viewRef;
this.attached.emit(viewRef);
return viewRef;
}
/** Gets the root node of the portal outlet. */
_getRootNode() {
const nativeElement = this._viewContainerRef.element.nativeElement;
return nativeElement.nodeType === nativeElement.ELEMENT_NODE ? nativeElement : nativeElement.parentNode;
}
};
_CdkPortalOutlet.ɵfac = function CdkPortalOutlet_Factory(t) {
return new (t || _CdkPortalOutlet)(ɵɵdirectiveInject(ComponentFactoryResolver$1), ɵɵdirectiveInject(ViewContainerRef), ɵɵdirectiveInject(DOCUMENT));
};
_CdkPortalOutlet.ɵdir = ɵɵdefineDirective({
type: _CdkPortalOutlet,
selectors: [["", "cdkPortalOutlet", ""]],
inputs: {
portal: ["cdkPortalOutlet", "portal"]
},
outputs: {
attached: "attached"
},
exportAs: ["cdkPortalOutlet"],
features: [ɵɵInheritDefinitionFeature]
});
var CdkPortalOutlet = _CdkPortalOutlet;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CdkPortalOutlet, [{
type: Directive,
args: [{
selector: "[cdkPortalOutlet]",
exportAs: "cdkPortalOutlet",
inputs: ["portal: cdkPortalOutlet"]
}]
}], () => [{
type: ComponentFactoryResolver$1
}, {
type: ViewContainerRef
}, {
type: void 0,
decorators: [{
type: Inject,
args: [DOCUMENT]
}]
}], {
attached: [{
type: Output
}]
});
})();
var _PortalHostDirective = class _PortalHostDirective extends CdkPortalOutlet {
};
_PortalHostDirective.ɵfac = (() => {
let ɵPortalHostDirective_BaseFactory;
return function PortalHostDirective_Factory(t) {
return (ɵPortalHostDirective_BaseFactory || (ɵPortalHostDirective_BaseFactory = ɵɵgetInheritedFactory(_PortalHostDirective)))(t || _PortalHostDirective);
};
})();
_PortalHostDirective.ɵdir = ɵɵdefineDirective({
type: _PortalHostDirective,
selectors: [["", "cdkPortalHost", ""], ["", "portalHost", ""]],
inputs: {
portal: ["cdkPortalHost", "portal"]
},
exportAs: ["cdkPortalHost"],
features: [ɵɵProvidersFeature([{
provide: CdkPortalOutlet,
useExisting: _PortalHostDirective
}]), ɵɵInheritDefinitionFeature]
});
var PortalHostDirective = _PortalHostDirective;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(PortalHostDirective, [{
type: Directive,
args: [{
selector: "[cdkPortalHost], [portalHost]",
exportAs: "cdkPortalHost",
inputs: ["portal: cdkPortalHost"],
providers: [{
provide: CdkPortalOutlet,
useExisting: PortalHostDirective
}]
}]
}], null, null);
})();
var _PortalModule = class _PortalModule {
};
_PortalModule.ɵfac = function PortalModule_Factory(t) {
return new (t || _PortalModule)();
};
_PortalModule.ɵmod = ɵɵdefineNgModule({
type: _PortalModule,
declarations: [CdkPortal, CdkPortalOutlet, TemplatePortalDirective, PortalHostDirective],
exports: [CdkPortal, CdkPortalOutlet, TemplatePortalDirective, PortalHostDirective]
});
_PortalModule.ɵinj = ɵɵdefineInjector({});
var PortalModule = _PortalModule;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(PortalModule, [{
type: NgModule,
args: [{
exports: [CdkPortal, CdkPortalOutlet, TemplatePortalDirective, PortalHostDirective],
declarations: [CdkPortal, CdkPortalOutlet, TemplatePortalDirective, PortalHostDirective]
}]
}], null, null);
})();
// node_modules/@angular/cdk/fesm2022/overlay.mjs
var scrollBehaviorSupported = supportsScrollBehavior();
var BlockScrollStrategy = class {
constructor(_viewportRuler, document2) {
this._viewportRuler = _viewportRuler;
this._previousHTMLStyles = {
top: "",
left: ""
};
this._isEnabled = false;
this._document = document2;
}
/** Attaches this scroll strategy to an overlay. */
attach() {
}
/** Blocks page-level scroll while the attached overlay is open. */
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;
}
}
/** Unblocks page-level scroll while the attached overlay is open. */
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 body = this._document.body;
const viewport = this._viewportRuler.getViewportSize();
return body.scrollHeight > viewport.height || body.scrollWidth > viewport.width;
}
};
function getMatScrollStrategyAlreadyAttachedError() {
return Error(`Scroll strategy has already been attached.`);
}
var CloseScrollStrategy = class {
constructor(_scrollDispatcher, _ngZone, _viewportRuler, _config) {
this._scrollDispatcher = _scrollDispatcher;
this._ngZone = _ngZone;
this._viewportRuler = _viewportRuler;
this._config = _config;
this._scrollSubscription = null;
this._detach = () => {
this.disable();
if (this._overlayRef.hasAttached()) {
this._ngZone.run(() => this._overlayRef.detach());
}
};
}
/** Attaches this scroll strategy to an overlay. */
attach(overlayRef) {
if (this._overlayRef && (typeof ngDevMode === "undefined" || ngDevMode)) {
throw getMatScrollStrategyAlreadyAttachedError();
}
this._overlayRef = overlayRef;
}
/** Enables the closing of the attached overlay on scroll. */
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);
}
}
/** Disables the closing the attached overlay on scroll. */
disable() {
if (this._scrollSubscription) {
this._scrollSubscription.unsubscribe();
this._scrollSubscription = null;
}
}
detach() {
this.disable();
this._overlayRef = null;
}
};
var NoopScrollStrategy = class {
/** Does nothing, as this scroll strategy is a no-op. */
enable() {
}
/** Does nothing, as this scroll strategy is a no-op. */
disable() {
}
/** Does nothing, as this scroll strategy is a no-op. */
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;
});
}
var RepositionScrollStrategy = class {
constructor(_scrollDispatcher, _viewportRuler, _ngZone, _config) {
this._scrollDispatcher = _scrollDispatcher;
this._viewportRuler = _viewportRuler;
this._ngZone = _ngZone;
this._config = _config;
this._scrollSubscription = null;
}
/** Attaches this scroll strategy to an overlay. */
attach(overlayRef) {
if (this._overlayRef && (typeof ngDevMode === "undefined" || ngDevMode)) {
throw getMatScrollStrategyAlreadyAttachedError();
}
this._overlayRef = overlayRef;
}
/** Enables repositioning of the attached overlay on scroll. */
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());
}
}
});
}
}
/** Disables repositioning of the attached overlay on scroll. */
disable() {
if (this._scrollSubscription) {
this._scrollSubscription.unsubscribe();
this._scrollSubscription = null;
}
}
detach() {
this.disable();
this._overlayRef = null;
}
};
var _ScrollStrategyOptions = class _ScrollStrategyOptions {
constructor(_scrollDispatcher, _viewportRuler, _ngZone, document2) {
this._scrollDispatcher = _scrollDispatcher;
this._viewportRuler = _viewportRuler;
this._ngZone = _ngZone;
this.noop = () => new NoopScrollStrategy();
this.close = (config) => new CloseScrollStrategy(this._scrollDispatcher, this._ngZone, this._viewportRuler, config);
this.block = () => new BlockScrollStrategy(this._viewportRuler, this._document);
this.reposition = (config) => new RepositionScrollStrategy(this._scrollDispatcher, this._viewportRuler, this._ngZone, config);
this._document = document2;
}
};
_ScrollStrategyOptions.ɵfac = function ScrollStrategyOptions_Factory(t) {
return new (t || _ScrollStrategyOptions)(ɵɵinject(ScrollDispatcher), ɵɵinject(ViewportRuler), ɵɵinject(NgZone), ɵɵinject(DOCUMENT));
};
_ScrollStrategyOptions.ɵprov = ɵɵdefineInjectable({
token: _ScrollStrategyOptions,
factory: _ScrollStrategyOptions.ɵfac,
providedIn: "root"
});
var ScrollStrategyOptions = _ScrollStrategyOptions;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ScrollStrategyOptions, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: ScrollDispatcher
}, {
type: ViewportRuler
}, {
type: NgZone
}, {
type: void 0,
decorators: [{
type: Inject,
args: [DOCUMENT]
}]
}], null);
})();
var OverlayConfig = class {
constructor(config) {
this.scrollStrategy = new NoopScrollStrategy();
this.panelClass = "";
this.hasBackdrop = false;
this.backdropClass = "cdk-overlay-dark-backdrop";
this.disposeOnNavigation = false;
if (config) {
const configKeys = Object.keys(config);
for (const key of configKeys) {
if (config[key] !== void 0) {
this[key] = config[key];
}
}
}
}
};
var ConnectionPositionPair = class {
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;
}
};
var ConnectedOverlayPositionChange = class {
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".`);
}
}
var _BaseOverlayDispatcher = class _BaseOverlayDispatcher {
constructor(document2) {
this._attachedOverlays = [];
this._document = document2;
}
ngOnDestroy() {
this.detach();
}
/** Add a new overlay to the list of attached overlay refs. */
add(overlayRef) {
this.remove(overlayRef);
this._attachedOverlays.push(overlayRef);
}
/** Remove an overlay from the list of attached overlay refs. */
remove(overlayRef) {
const index = this._attachedOverlays.indexOf(overlayRef);
if (index > -1) {
this._attachedOverlays.splice(index, 1);
}
if (this._attachedOverlays.length === 0) {
this.detach();
}
}
};
_BaseOverlayDispatcher.ɵfac = function BaseOverlayDispatcher_Factory(t) {
return new (t || _BaseOverlayDispatcher)(ɵɵinject(DOCUMENT));
};
_BaseOverlayDispatcher.ɵprov = ɵɵdefineInjectable({
token: _BaseOverlayDispatcher,
factory: _BaseOverlayDispatcher.ɵfac,
providedIn: "root"
});
var BaseOverlayDispatcher = _BaseOverlayDispatcher;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(BaseOverlayDispatcher, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: void 0,
decorators: [{
type: Inject,
args: [DOCUMENT]
}]
}], null);
})();
var _OverlayKeyboardDispatcher = class _OverlayKeyboardDispatcher extends BaseOverlayDispatcher {
constructor(document2, _ngZone) {
super(document2);
this._ngZone = _ngZone;
this._keydownListener = (event) => {
const overlays = this._attachedOverlays;
for (let i = overlays.length - 1; i > -1; i--) {
if (overlays[i]._keydownEvents.observers.length > 0) {
const keydownEvents = overlays[i]._keydownEvents;
if (this._ngZone) {
this._ngZone.run(() => keydownEvents.next(event));
} else {
keydownEvents.next(event);
}
break;
}
}
};
}
/** Add a new overlay to the list of attached overlay refs. */
add(overlayRef) {
super.add(overlayRef);
if (!this._isAttached) {
if (this._ngZone) {
this._ngZone.runOutsideAngular(() => this._document.body.addEventListener("keydown", this._keydownListener));
} else {
this._document.body.addEventListener("keydown", this._keydownListener);
}
this._isAttached = true;
}
}
/** Detaches the global keyboard event listener. */
detach() {
if (this._isAttached) {
this._document.body.removeEventListener("keydown", this._keydownListener);
this._isAttached = false;
}
}
};
_OverlayKeyboardDispatcher.ɵfac = function OverlayKeyboardDispatcher_Factory(t) {
return new (t || _OverlayKeyboardDispatcher)(ɵɵinject(DOCUMENT), ɵɵinject(NgZone, 8));
};
_OverlayKeyboardDispatcher.ɵprov = ɵɵdefineInjectable({
token: _OverlayKeyboardDispatcher,
factory: _OverlayKeyboardDispatcher.ɵfac,
providedIn: "root"
});
var OverlayKeyboardDispatcher = _OverlayKeyboardDispatcher;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(OverlayKeyboardDispatcher, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: void 0,
decorators: [{
type: Inject,
args: [DOCUMENT]
}]
}, {
type: NgZone,
decorators: [{
type: Optional
}]
}], null);
})();
var _OverlayOutsideClickDispatcher = class _OverlayOutsideClickDispatcher extends BaseOverlayDispatcher {
constructor(document2, _platform, _ngZone) {
super(document2);
this._platform = _platform;
this._ngZone = _ngZone;
this._cursorStyleIsSet = false;
this._pointerDownListener = (event) => {
this._pointerDownEventTarget = _getEventTarget(event);
};
this._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 (overlayRef.overlayElement.contains(target) || overlayRef.overlayElement.contains(origin)) {
break;
}
const outsidePointerEvents = overlayRef._outsidePointerEvents;
if (this._ngZone) {
this._ngZone.run(() => outsidePointerEvents.next(event));
} else {
outsidePointerEvents.next(event);
}
}
};
}
/** Add a new overlay to the list of attached overlay refs. */
add(overlayRef) {
super.add(overlayRef);
if (!this._isAttached) {
const body = this._document.body;
if (this._ngZone) {
this._ngZone.runOutsideAngular(() => this._addEventListeners(body));
} else {
this._addEventListeners(body);
}
if (this._platform.IOS && !this._cursorStyleIsSet) {
this._cursorOriginalValue = body.style.cursor;
body.style.cursor = "pointer";
this._cursorStyleIsSet = true;
}
this._isAttached = true;
}
}
/** Detaches the global keyboard event listener. */
detach() {
if (this._isAttached) {
const body = this._document.body;
body.removeEventListener("pointerdown", this._pointerDownListener, true);
body.removeEventListener("click", this._clickListener, true);
body.removeEventListener("auxclick", this._clickListener, true);
body.removeEventListener("contextmenu", this._clickListener, true);
if (this._platform.IOS && this._cursorStyleIsSet) {
body.style.cursor = this._cursorOriginalValue;
this._cursorStyleIsSet = false;
}
this._isAttached = false;
}
}
_addEventListeners(body) {
body.addEventListener("pointerdown", this._pointerDownListener, true);
body.addEventListener("click", this._clickListener, true);
body.addEventListener("auxclick", this._clickListener, true);
body.addEventListener("contextmenu", this._clickListener, true);
}
};
_OverlayOutsideClickDispatcher.ɵfac = function OverlayOutsideClickDispatcher_Factory(t) {
return new (t || _OverlayOutsideClickDispatcher)(ɵɵinject(DOCUMENT), ɵɵinject(Platform), ɵɵinject(NgZone, 8));
};
_OverlayOutsideClickDispatcher.ɵprov = ɵɵdefineInjectable({
token: _OverlayOutsideClickDispatcher,
factory: _OverlayOutsideClickDispatcher.ɵfac,
providedIn: "root"
});
var OverlayOutsideClickDispatcher = _OverlayOutsideClickDispatcher;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(OverlayOutsideClickDispatcher, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: void 0,
decorators: [{
type: Inject,
args: [DOCUMENT]
}]
}, {
type: Platform
}, {
type: NgZone,
decorators: [{
type: Optional
}]
}], null);
})();
var _OverlayContainer = class _OverlayContainer {
constructor(document2, _platform) {
this._platform = _platform;
this._document = document2;
}
ngOnDestroy() {
this._containerElement?.remove();
}
/**
* This method returns the overlay container element. It will lazily
* create the element the first time it is called to facilitate using
* the container in non-browser environments.
* @returns the container element
*/
getContainerElement() {
if (!this._containerElement) {
this._createContainer();
}
return this._containerElement;
}
/**
* Create the overlay container element, which is simply a div
* with the 'cdk-overlay-container' class on the document body.
*/
_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;
}
};
_OverlayContainer.ɵfac = function OverlayContainer_Factory(t) {
return new (t || _OverlayContainer)(ɵɵinject(DOCUMENT), ɵɵinject(Platform));
};
_OverlayContainer.ɵprov = ɵɵdefineInjectable({
token: _OverlayContainer,
factory: _OverlayContainer.ɵfac,
providedIn: "root"
});
var OverlayContainer = _OverlayContainer;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(OverlayContainer, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: void 0,
decorators: [{
type: Inject,
args: [DOCUMENT]
}]
}, {
type: Platform
}], null);
})();
var OverlayRef = class {
constructor(_portalOutlet, _host, _pane, _config, _ngZone, _keyboardDispatcher, _document, _location, _outsideClickDispatcher, _animationsDisabled = false) {
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._backdropElement = null;
this._backdropClick = new Subject();
this._attachments = new Subject();
this._detachments = new Subject();
this._locationChanges = Subscription.EMPTY;
this._backdropClickHandler = (event) => this._backdropClick.next(event);
this._backdropTransitionendHandler = (event) => {
this._disposeBackdrop(event.target);
};
this._keydownEvents = new Subject();
this._outsidePointerEvents = new Subject();
if (_config.scrollStrategy) {
this._scrollStrategy = _config.scrollStrategy;
this._scrollStrategy.attach(this);
}
this._positionStrategy = _config.positionStrategy;
}
/** The overlay's HTML element */
get overlayElement() {
return this._pane;
}
/** The overlay's backdrop HTML element. */
get backdropElement() {
return this._backdropElement;
}
/**
* Wrapper around the panel element. Can be used for advanced
* positioning where a wrapper with specific styling is
* required around the overlay pane.
*/
get hostElement() {
return this._host;
}
/**
* Attaches content, given via a Portal, to the overlay.
* If the overlay is configured to have a backdrop, it will be created.
*
* @param portal Portal instance to which to attach the overlay.
* @returns The portal attachment result.
*/
attach(portal) {
if (!this._host.parentElement && this._previousHostParent) {
this._previousHostParent.appendChild(this._host);
}
const attachResult = this._portalOutlet.attach(portal);
if (this._positionStrategy) {
this._positionStrategy.attach(this);
}
this._updateStackingOrder();
this._updateElementSize();
this._updateElementDirection();
if (this._scrollStrategy) {
this._scrollStrategy.enable();
}
this._ngZone.onStable.pipe(take(1)).subscribe(() => {
if (this.hasAttached()) {
this.updatePosition();
}
});
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._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;
}
/**
* Detaches an overlay from a portal.
* @returns The portal detachment result.
*/
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._keyboardDispatcher.remove(this);
this._detachContentWhenStable();
this._locationChanges.unsubscribe();
this._outsideClickDispatcher.remove(this);
return detachmentResult;
}
/** Cleans up the overlay from the DOM. */
dispose() {
const isAttached = this.hasAttached();
if (this._positionStrategy) {
this._positionStrategy.dispose();
}
this._disposeScrollStrategy();
this._disposeBackdrop(this._backdropElement);
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._previousHostParent = this._pane = this._host = null;
if (isAttached) {
this._detachments.next();
}
this._detachments.complete();
}
/** Whether the overlay has attached content. */
hasAttached() {
return this._portalOutlet.hasAttached();
}
/** Gets an observable that emits when the backdrop has been clicked. */
backdropClick() {
return this._backdropClick;
}
/** Gets an observable that emits when the overlay has been attached. */
attachments() {
return this._attachments;
}
/** Gets an observable that emits when the overlay has been detached. */
detachments() {
return this._detachments;
}
/** Gets an observable of keydown events targeted to this overlay. */
keydownEvents() {
return this._keydownEvents;
}
/** Gets an observable of pointer events targeted outside this overlay. */
outsidePointerEvents() {
return this._outsidePointerEvents;
}
/** Gets the current overlay configuration, which is immutable. */
getConfig() {
return this._config;
}
/** Updates the position of the overlay based on the position strategy. */
updatePosition() {
if (this._positionStrategy) {
this._positionStrategy.apply();
}
}
/** Switches to a new position strategy and updates the overlay position. */
updatePositionStrategy(strategy) {
if (strategy === this._positionStrategy) {
return;
}
if (this._positionStrategy) {
this._positionStrategy.dispose();
}
this._positionStrategy = strategy;
if (this.hasAttached()) {
strategy.attach(this);
this.updatePosition();
}
}
/** Update the size properties of the overlay. */
updateSize(sizeConfig) {
this._config = __spreadValues(__spreadValues({}, this._config), sizeConfig);
this._updateElementSize();
}
/** Sets the LTR/RTL direction for the overlay. */
setDirection(dir) {
this._config = __spreadProps(__spreadValues({}, this._config), {
direction: dir
});
this._updateElementDirection();
}
/** Add a CSS class or an array of classes to the overlay pane. */
addPanelClass(classes) {
if (this._pane) {
this._toggleClasses(this._pane, classes, true);
}
}
/** Remove a CSS class or an array of classes from the overlay pane. */
removePanelClass(classes) {
if (this._pane) {
this._toggleClasses(this._pane, classes, false);
}
}
/**
* Returns the layout direction of the overlay panel.
*/
getDirection() {
const direction = this._config.direction;
if (!direction) {
return "ltr";
}
return typeof direction === "string" ? direction : direction.value;
}
/** Switches to a new scroll strategy. */
updateScrollStrategy(strategy) {
if (strategy === this._scrollStrategy) {
return;
}
this._disposeScrollStrategy();
this._scrollStrategy = strategy;
if (this.hasAttached()) {
strategy.attach(this);
strategy.enable();
}
}
/** Updates the text direction of the overlay panel. */
_updateElementDirection() {
this._host.setAttribute("dir", this.getDirection());
}
/** Updates the size of the overlay element based on the overlay config. */
_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);
}
/** Toggles the pointer events for the overlay pane element. */
_togglePointerEvents(enablePointer) {
this._pane.style.pointerEvents = enablePointer ? "" : "none";
}
/** Attaches a backdrop for this overlay. */
_attachBackdrop() {
const showingClass = "cdk-overlay-backdrop-showing";
this._backdropElement = this._document.createElement("div");
this._backdropElement.classList.add("cdk-overlay-backdrop");
if (this._animationsDisabled) {
this._backdropElement.classList.add("cdk-overlay-backdrop-noop-animation");
}
if (this._config.backdropClass) {
this._toggleClasses(this._backdropElement, this._config.backdropClass, true);
}
this._host.parentElement.insertBefore(this._backdropElement, this._host);
this._backdropElement.addEventListener("click", this._backdropClickHandler);
if (!this._animationsDisabled && typeof requestAnimationFrame !== "undefined") {
this._ngZone.runOutsideAngular(() => {
requestAnimationFrame(() => {
if (this._backdropElement) {
this._backdropElement.classList.add(showingClass);
}
});
});
} else {
this._backdropElement.classList.add(showingClass);
}
}
/**
* Updates the stacking order of the element, moving it to the top if necessary.
* This is required in cases where one overlay was detached, while another one,
* that should be behind it, was destroyed. The next time both of them are opened,
* the stacking will be wrong, because the detached element's pane will still be
* in its original DOM position.
*/
_updateStackingOrder() {
if (this._host.nextSibling) {
this._host.parentNode.appendChild(this._host);
}
}
/** Detaches the backdrop (if any) associated with the overlay. */
detachBackdrop() {
const backdropToDetach = this._backdropElement;
if (!backdropToDetach) {
return;
}
if (this._animationsDisabled) {
this._disposeBackdrop(backdropToDetach);
return;
}
backdropToDetach.classList.remove("cdk-overlay-backdrop-showing");
this._ngZone.runOutsideAngular(() => {
backdropToDetach.addEventListener("transitionend", this._backdropTransitionendHandler);
});
backdropToDetach.style.pointerEvents = "none";
this._backdropTimeout = this._ngZone.runOutsideAngular(() => setTimeout(() => {
this._disposeBackdrop(backdropToDetach);
}, 500));
}
/** Toggles a single CSS class or an array of classes on an element. */
_toggleClasses(element, cssClasses, isAdd) {
const classes = coerceArray(cssClasses || []).filter((c) => !!c);
if (classes.length) {
isAdd ? element.classList.add(...classes) : element.classList.remove(...classes);
}
}
/** Detaches the overlay content next time the zone stabilizes. */
_detachContentWhenStable() {
this._ngZone.runOutsideAngular(() => {
const subscription = this._ngZone.onStable.pipe(takeUntil(merge(this._attachments, this._detachments))).subscribe(() => {
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();
}
subscription.unsubscribe();
}
});
});
}
/** Disposes of a scroll strategy. */
_disposeScrollStrategy() {
const scrollStrategy = this._scrollStrategy;
if (scrollStrategy) {
scrollStrategy.disable();
if (scrollStrategy.detach) {
scrollStrategy.detach();
}
}
}
/** Removes a backdrop element from the DOM. */
_disposeBackdrop(backdrop) {
if (backdrop) {
backdrop.removeEventListener("click", this._backdropClickHandler);
backdrop.removeEventListener("transitionend", this._backdropTransitionendHandler);
backdrop.remove();
if (this._backdropElement === backdrop) {
this._backdropElement = null;
}
}
if (this._backdropTimeout) {
clearTimeout(this._backdropTimeout);
this._backdropTimeout = void 0;
}
}
};
var boundingBoxClass = "cdk-overlay-connected-position-bounding-box";
var cssUnitPattern = /([A-Za-z%]+)$/;
var FlexibleConnectedPositionStrategy = class {
/** Ordered list of preferred positions, from most to least desirable. */
get positions() {
return this._preferredPositions;
}
constructor(connectedTo, _viewportRuler, _document, _platform, _overlayContainer) {
this._viewportRuler = _viewportRuler;
this._document = _document;
this._platform = _platform;
this._overlayContainer = _overlayContainer;
this._lastBoundingBoxSize = {
width: 0,
height: 0
};
this._isPushed = false;
this._canPush = true;
this._growAfterOpen = false;
this._hasFlexibleDimensions = true;
this._positionLocked = false;
this._viewportMargin = 0;
this._scrollables = [];
this._preferredPositions = [];
this._positionChanges = new Subject();
this._resizeSubscription = Subscription.EMPTY;
this._offsetX = 0;
this._offsetY = 0;
this._appliedPanelClasses = [];
this.positionChanges = this._positionChanges;
this.setOrigin(connectedTo);
}
/** Attaches this position strategy to an overlay. */
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();
});
}
/**
* Updates the position of the overlay element, using whichever preferred position relative
* to the origin best fits on-screen.
*
* The selection of a position goes as follows:
* - If any positions fit completely within the viewport as-is,
* choose the first position that does so.
* - If flexible dimensions are enabled and at least one satisfies the given minimum width/height,
* choose the position with the greatest available size modified by the positions' weight.
* - If pushing is enabled, take the position that went off-screen the least and push it
* on-screen.
* - If none of the previous criteria were met, use the position that goes off-screen the least.
* @docs-private
*/
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();
}
/** Cleanup after the element gets destroyed. */
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;
}
/**
* This re-aligns the overlay element with the trigger in its last calculated position,
* even if a position higher in the "preferred positions" list would now fit. This
* allows one to re-align the panel without changing the orientation of the panel.
*/
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();
}
}
/**
* Sets the list of Scrollable containers that host the origin element so that
* on reposition we can evaluate if it or the overlay has been clipped or outside view. Every
* Scrollable must be an ancestor element of the strategy's origin element.
*/
withScrollableContainers(scrollables) {
this._scrollables = scrollables;
return this;
}
/**
* Adds new preferred positions.
* @param positions List of positions options for this overlay.
*/
withPositions(positions) {
this._preferredPositions = positions;
if (positions.indexOf(this._lastPosition) === -1) {
this._lastPosition = null;
}
this._validatePositions();
return this;
}
/**
* Sets a minimum distance the overlay may be positioned to the edge of the viewport.
* @param margin Required margin between the overlay and the viewport edge in pixels.
*/
withViewportMargin(margin) {
this._viewportMargin = margin;
return this;
}
/** Sets whether the overlay's width and height can be constrained to fit within the viewport. */
withFlexibleDimensions(flexibleDimensions = true) {
this._hasFlexibleDimensions = flexibleDimensions;
return this;
}
/** Sets whether the overlay can grow after the initial open via flexible width/height. */
withGrowAfterOpen(growAfterOpen = true) {
this._growAfterOpen = growAfterOpen;
return this;
}
/** Sets whether the overlay can be pushed on-screen if none of the provided positions fit. */
withPush(canPush = true) {
this._canPush = canPush;
return this;
}
/**
* Sets whether the overlay's position should be locked in after it is positioned
* initially. When an overlay is locked in, it won't attempt to reposition itself
* when the position is re-applied (e.g. when the user scrolls away).
* @param isLocked Whether the overlay should locked in.
*/
withLockedPosition(isLocked = true) {
this._positionLocked = isLocked;
return this;
}
/**
* Sets the origin, relative to which to position the overlay.
* Using an element origin is useful for building components that need to be positioned
* relatively to a trigger (e.g. dropdown menus or tooltips), whereas using a point can be
* used for cases like contextual menus which open relative to the user's pointer.
* @param origin Reference to the new origin.
*/
setOrigin(origin) {
this._origin = origin;
return this;
}
/**
* Sets the default offset for the overlay's connection point on the x-axis.
* @param offset New offset in the X axis.
*/
withDefaultOffsetX(offset) {
this._offsetX = offset;
return this;
}
/**
* Sets the default offset for the overlay's connection point on the y-axis.
* @param offset New offset in the Y axis.
*/
withDefaultOffsetY(offset) {
this._offsetY = offset;
return this;
}
/**
* Configures that the position strategy should set a `transform-origin` on some elements
* inside the overlay, depending on the current position that is being applied. This is
* useful for the cases where the origin of an animation can change depending on the
* alignment of the overlay.
* @param selector CSS selector that will be used to find the target
* elements onto which to set the transform origin.
*/
withTransformOriginOn(selector) {
this._transformOriginSelector = selector;
return this;
}
/**
* Gets the (x, y) coordinate of a connection point on the origin based on a relative position.
*/
_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
};
}
/**
* Gets the (x, y) coordinate of the top-left corner of the overlay given a given position and
* origin point to which the overlay should be connected.
*/
_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
};
}
/** Gets how well an overlay at the given point will fit within the viewport. */
_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
};
}
/**
* Whether the overlay can fit within the viewport when it may resize either its width or height.
* @param fit How well the overlay fits in the viewport at some position.
* @param point The (x, y) coordinates of the overlay at some position.
* @param viewport The geometry of the viewport.
*/
_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;
}
/**
* Gets the point at which the overlay can be "pushed" on-screen. If the overlay is larger than
* the viewport, the top-left corner will be pushed on-screen (with overflow occurring on the
* right and bottom).
*
* @param start Starting point from which the overlay is pushed.
* @param rawOverlayRect Dimensions of the overlay.
* @param scrollPosition Current viewport scroll position.
* @returns The point at which to position the overlay after pushing. This is effectively a new
* originPoint.
*/
_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._viewportMargin ? viewport.left - scrollPosition.left - start.x : 0;
}
if (overlay.height <= viewport.height) {
pushY = overflowTop || -overflowBottom;
} else {
pushY = start.y < this._viewportMargin ? viewport.top - scrollPosition.top - start.y : 0;
}
this._previousPushAmount = {
x: pushX,
y: pushY
};
return {
x: start.x + pushX,
y: start.y + pushY
};
}
/**
* Applies a computed position to the overlay and emits a position change.
* @param position The position preference
* @param originPoint The point on the origin element where the overlay is connected.
*/
_applyPosition(position, originPoint) {
this._setTransformOrigin(position);
this._setOverlayElementStyles(originPoint, position);
this._setBoundingBoxStyles(originPoint, position);
if (position.panelClass) {
this._addPanelClasses(position.panelClass);
}
this._lastPosition = position;
if (this._positionChanges.observers.length) {
const scrollableViewProperties = this._getScrollVisibility();
const changeEvent = new ConnectedOverlayPositionChange(position, scrollableViewProperties);
this._positionChanges.next(changeEvent);
}
this._isInitialRender = false;
}
/** Sets the transform origin based on the configured selector and the passed-in position. */
_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}`;
}
}
/**
* Gets the position and size of the overlay's sizing container.
*
* This method does no measuring and applies no styles so that we can cheaply compute the
* bounds for all positions and choose the best fit based on these results.
*/
_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._viewportMargin;
} else if (position.overlayY === "bottom") {
bottom = viewport.height - origin.y + this._viewportMargin * 2;
height = viewport.height - bottom + this._viewportMargin;
} 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._viewportMargin;
width = origin.x - this._viewportMargin;
} else if (isBoundedByRightViewportEdge) {
left = origin.x;
width = viewport.right - origin.x;
} 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,
left,
bottom,
right,
width,
height
};
}
/**
* Sets the position and size of the overlay's sizing wrapper. The wrapper is positioned on the
* origin's connection point and stretches to the bounds of the viewport.
*
* @param origin The point on the origin element where the overlay is connected.
* @param position The position preference
*/
_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 = styles.maxHeight = styles.maxWidth = "";
styles.width = styles.height = "100%";
} else {
const maxHeight = this._overlayRef.getConfig().maxHeight;
const maxWidth = this._overlayRef.getConfig().maxWidth;
styles.height = coerceCssPixelValue(boundingBoxRect.height);
styles.top = coerceCssPixelValue(boundingBoxRect.top);
styles.bottom = coerceCssPixelValue(boundingBoxRect.bottom);
styles.width = coerceCssPixelValue(boundingBoxRect.width);
styles.left = coerceCssPixelValue(boundingBoxRect.left);
styles.right = coerceCssPixelValue(boundingBoxRect.right);
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);
}
/** Resets the styles for the bounding box so that a new positioning can be computed. */
_resetBoundingBoxStyles() {
extendStyles(this._boundingBox.style, {
top: "0",
left: "0",
right: "0",
bottom: "0",
height: "",
width: "",
alignItems: "",
justifyContent: ""
});
}
/** Resets the styles for the overlay pane so that a new positioning can be computed. */
_resetOverlayElementStyles() {
extendStyles(this._pane.style, {
top: "",
left: "",
bottom: "",
right: "",
position: "",
transform: ""
});
}
/** Sets positioning styles to the overlay element. */
_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);
}
/** Gets the exact top/bottom for the overlay when not using flexible sizing or when pushing. */
_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;
}
/** Gets the exact left/right for the overlay when not using flexible sizing or when pushing. */
_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;
}
/**
* Gets the view properties of the trigger and overlay, including whether they are clipped
* or completely outside the view of any of the strategy's scrollables.
*/
_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)
};
}
/** Subtracts the amount that an element is overflowing on an axis from its length. */
_subtractOverflows(length, ...overflows) {
return overflows.reduce((currentValue, currentOverflow) => {
return currentValue - Math.max(currentOverflow, 0);
}, length);
}
/** Narrows the given viewport rect by the current _viewportMargin. */
_getNarrowedViewportRect() {
const width = this._document.documentElement.clientWidth;
const height = this._document.documentElement.clientHeight;
const scrollPosition = this._viewportRuler.getViewportScrollPosition();
return {
top: scrollPosition.top + this._viewportMargin,
left: scrollPosition.left + this._viewportMargin,
right: scrollPosition.left + width - this._viewportMargin,
bottom: scrollPosition.top + height - this._viewportMargin,
width: width - 2 * this._viewportMargin,
height: height - 2 * this._viewportMargin
};
}
/** Whether the we're dealing with an RTL context */
_isRtl() {
return this._overlayRef.getDirection() === "rtl";
}
/** Determines whether the overlay uses exact or flexible positioning. */
_hasExactPosition() {
return !this._hasFlexibleDimensions || this._isPushed;
}
/** Retrieves the offset of a position along the x or y axis. */
_getOffset(position, axis) {
if (axis === "x") {
return position.offsetX == null ? this._offsetX : position.offsetX;
}
return position.offsetY == null ? this._offsetY : position.offsetY;
}
/** Validates that the current position match the expected values. */
_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);
});
}
}
/** Adds a single CSS class or an array of classes on the overlay panel. */
_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);
}
});
}
}
/** Clears the classes that the position strategy has applied from the overlay panel. */
_clearPanelClasses() {
if (this._pane) {
this._appliedPanelClasses.forEach((cssClass) => {
this._pane.classList.remove(cssClass);
});
this._appliedPanelClasses = [];
}
}
/** Returns the ClientRect of the current origin. */
_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
};
}
};
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)
};
}
var wrapperClass = "cdk-global-overlay-wrapper";
var GlobalPositionStrategy = class {
constructor() {
this._cssPosition = "static";
this._topOffset = "";
this._bottomOffset = "";
this._alignItems = "";
this._xPosition = "";
this._xOffset = "";
this._width = "";
this._height = "";
this._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;
}
/**
* Sets the top position of the overlay. Clears any previously set vertical position.
* @param value New top offset.
*/
top(value = "") {
this._bottomOffset = "";
this._topOffset = value;
this._alignItems = "flex-start";
return this;
}
/**
* Sets the left position of the overlay. Clears any previously set horizontal position.
* @param value New left offset.
*/
left(value = "") {
this._xOffset = value;
this._xPosition = "left";
return this;
}
/**
* Sets the bottom position of the overlay. Clears any previously set vertical position.
* @param value New bottom offset.
*/
bottom(value = "") {
this._topOffset = "";
this._bottomOffset = value;
this._alignItems = "flex-end";
return this;
}
/**
* Sets the right position of the overlay. Clears any previously set horizontal position.
* @param value New right offset.
*/
right(value = "") {
this._xOffset = value;
this._xPosition = "right";
return this;
}
/**
* Sets the overlay to the start of the viewport, depending on the overlay direction.
* This will be to the left in LTR layouts and to the right in RTL.
* @param offset Offset from the edge of the screen.
*/
start(value = "") {
this._xOffset = value;
this._xPosition = "start";
return this;
}
/**
* Sets the overlay to the end of the viewport, depending on the overlay direction.
* This will be to the right in LTR layouts and to the left in RTL.
* @param offset Offset from the edge of the screen.
*/
end(value = "") {
this._xOffset = value;
this._xPosition = "end";
return this;
}
/**
* Sets the overlay width and clears any previously set width.
* @param value New width for the overlay
* @deprecated Pass the `width` through the `OverlayConfig`.
* @breaking-change 8.0.0
*/
width(value = "") {
if (this._overlayRef) {
this._overlayRef.updateSize({
width: value
});
} else {
this._width = value;
}
return this;
}
/**
* Sets the overlay height and clears any previously set height.
* @param value New height for the overlay
* @deprecated Pass the `height` through the `OverlayConfig`.
* @breaking-change 8.0.0
*/
height(value = "") {
if (this._overlayRef) {
this._overlayRef.updateSize({
height: value
});
} else {
this._height = value;
}
return this;
}
/**
* Centers the overlay horizontally with an optional offset.
* Clears any previously set horizontal position.
*
* @param offset Overlay offset from the horizontal center.
*/
centerHorizontally(offset = "") {
this.left(offset);
this._xPosition = "center";
return this;
}
/**
* Centers the overlay vertically with an optional offset.
* Clears any previously set vertical position.
*
* @param offset Overlay offset from the vertical center.
*/
centerVertically(offset = "") {
this.top(offset);
this._alignItems = "center";
return this;
}
/**
* Apply the position to the element.
* @docs-private
*/
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;
}
/**
* Cleans up the DOM changes from the position strategy.
* @docs-private
*/
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;
}
};
var _OverlayPositionBuilder = class _OverlayPositionBuilder {
constructor(_viewportRuler, _document, _platform, _overlayContainer) {
this._viewportRuler = _viewportRuler;
this._document = _document;
this._platform = _platform;
this._overlayContainer = _overlayContainer;
}
/**
* Creates a global position strategy.
*/
global() {
return new GlobalPositionStrategy();
}
/**
* Creates a flexible position strategy.
* @param origin Origin relative to which to position the overlay.
*/
flexibleConnectedTo(origin) {
return new FlexibleConnectedPositionStrategy(origin, this._viewportRuler, this._document, this._platform, this._overlayContainer);
}
};
_OverlayPositionBuilder.ɵfac = function OverlayPositionBuilder_Factory(t) {
return new (t || _OverlayPositionBuilder)(ɵɵinject(ViewportRuler), ɵɵinject(DOCUMENT), ɵɵinject(Platform), ɵɵinject(OverlayContainer));
};
_OverlayPositionBuilder.ɵprov = ɵɵdefineInjectable({
token: _OverlayPositionBuilder,
factory: _OverlayPositionBuilder.ɵfac,
providedIn: "root"
});
var OverlayPositionBuilder = _OverlayPositionBuilder;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(OverlayPositionBuilder, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: ViewportRuler
}, {
type: void 0,
decorators: [{
type: Inject,
args: [DOCUMENT]
}]
}, {
type: Platform
}, {
type: OverlayContainer
}], null);
})();
var nextUniqueId = 0;
var _Overlay = class _Overlay {
constructor(scrollStrategies, _overlayContainer, _componentFactoryResolver, _positionBuilder, _keyboardDispatcher, _injector, _ngZone, _document, _directionality, _location, _outsideClickDispatcher, _animationsModuleType) {
this.scrollStrategies = scrollStrategies;
this._overlayContainer = _overlayContainer;
this._componentFactoryResolver = _componentFactoryResolver;
this._positionBuilder = _positionBuilder;
this._keyboardDispatcher = _keyboardDispatcher;
this._injector = _injector;
this._ngZone = _ngZone;
this._document = _document;
this._directionality = _directionality;
this._location = _location;
this._outsideClickDispatcher = _outsideClickDispatcher;
this._animationsModuleType = _animationsModuleType;
}
/**
* Creates an overlay.
* @param config Configuration applied to the overlay.
* @returns Reference to the created overlay.
*/
create(config) {
const host = this._createHostElement();
const pane = this._createPaneElement(host);
const portalOutlet = this._createPortalOutlet(pane);
const overlayConfig = new OverlayConfig(config);
overlayConfig.direction = overlayConfig.direction || this._directionality.value;
return new OverlayRef(portalOutlet, host, pane, overlayConfig, this._ngZone, this._keyboardDispatcher, this._document, this._location, this._outsideClickDispatcher, this._animationsModuleType === "NoopAnimations");
}
/**
* Gets a position builder that can be used, via fluent API,
* to construct and configure a position strategy.
* @returns An overlay position builder.
*/
position() {
return this._positionBuilder;
}
/**
* Creates the DOM element for an overlay and appends it to the overlay container.
* @returns Newly-created pane element
*/
_createPaneElement(host) {
const pane = this._document.createElement("div");
pane.id = `cdk-overlay-${nextUniqueId++}`;
pane.classList.add("cdk-overlay-pane");
host.appendChild(pane);
return pane;
}
/**
* Creates the host element that wraps around an overlay
* and can be used for advanced positioning.
* @returns Newly-create host element.
*/
_createHostElement() {
const host = this._document.createElement("div");
this._overlayContainer.getContainerElement().appendChild(host);
return host;
}
/**
* Create a DomPortalOutlet into which the overlay content can be loaded.
* @param pane The DOM element to turn into a portal outlet.
* @returns A portal outlet for the given DOM element.
*/
_createPortalOutlet(pane) {
if (!this._appRef) {
this._appRef = this._injector.get(ApplicationRef);
}
return new DomPortalOutlet(pane, this._componentFactoryResolver, this._appRef, this._injector, this._document);
}
};
_Overlay.ɵfac = function Overlay_Factory(t) {
return new (t || _Overlay)(ɵɵinject(ScrollStrategyOptions), ɵɵinject(OverlayContainer), ɵɵinject(ComponentFactoryResolver$1), ɵɵinject(OverlayPositionBuilder), ɵɵinject(OverlayKeyboardDispatcher), ɵɵinject(Injector), ɵɵinject(NgZone), ɵɵinject(DOCUMENT), ɵɵinject(Directionality), ɵɵinject(Location), ɵɵinject(OverlayOutsideClickDispatcher), ɵɵinject(ANIMATION_MODULE_TYPE, 8));
};
_Overlay.ɵprov = ɵɵdefineInjectable({
token: _Overlay,
factory: _Overlay.ɵfac,
providedIn: "root"
});
var Overlay = _Overlay;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Overlay, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: ScrollStrategyOptions
}, {
type: OverlayContainer
}, {
type: ComponentFactoryResolver$1
}, {
type: OverlayPositionBuilder
}, {
type: OverlayKeyboardDispatcher
}, {
type: Injector
}, {
type: NgZone
}, {
type: void 0,
decorators: [{
type: Inject,
args: [DOCUMENT]
}]
}, {
type: Directionality
}, {
type: Location
}, {
type: OverlayOutsideClickDispatcher
}, {
type: void 0,
decorators: [{
type: Inject,
args: [ANIMATION_MODULE_TYPE]
}, {
type: Optional
}]
}], null);
})();
var 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"
}];
var CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY = new InjectionToken("cdk-connected-overlay-scroll-strategy", {
providedIn: "root",
factory: () => {
const overlay = inject(Overlay);
return () => overlay.scrollStrategies.reposition();
}
});
var _CdkOverlayOrigin = class _CdkOverlayOrigin {
constructor(elementRef) {
this.elementRef = elementRef;
}
};
_CdkOverlayOrigin.ɵfac = function CdkOverlayOrigin_Factory(t) {
return new (t || _CdkOverlayOrigin)(ɵɵdirectiveInject(ElementRef));
};
_CdkOverlayOrigin.ɵdir = ɵɵdefineDirective({
type: _CdkOverlayOrigin,
selectors: [["", "cdk-overlay-origin", ""], ["", "overlay-origin", ""], ["", "cdkOverlayOrigin", ""]],
exportAs: ["cdkOverlayOrigin"],
standalone: true
});
var CdkOverlayOrigin = _CdkOverlayOrigin;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CdkOverlayOrigin, [{
type: Directive,
args: [{
selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]",
exportAs: "cdkOverlayOrigin",
standalone: true
}]
}], () => [{
type: ElementRef
}], null);
})();
var _CdkConnectedOverlay = class _CdkConnectedOverlay {
/** The offset in pixels for the overlay connection point on the x-axis */
get offsetX() {
return this._offsetX;
}
set offsetX(offsetX) {
this._offsetX = offsetX;
if (this._position) {
this._updatePositionStrategy(this._position);
}
}
/** The offset in pixels for the overlay connection point on the y-axis */
get offsetY() {
return this._offsetY;
}
set offsetY(offsetY) {
this._offsetY = offsetY;
if (this._position) {
this._updatePositionStrategy(this._position);
}
}
/** Whether the overlay should be disposed of when the user goes backwards/forwards in history. */
get disposeOnNavigation() {
return this._disposeOnNavigation;
}
set disposeOnNavigation(value) {
this._disposeOnNavigation = value;
}
// TODO(jelbourn): inputs for size, scroll behavior, animation, etc.
constructor(_overlay, templateRef, viewContainerRef, scrollStrategyFactory, _dir) {
this._overlay = _overlay;
this._dir = _dir;
this._backdropSubscription = Subscription.EMPTY;
this._attachSubscription = Subscription.EMPTY;
this._detachSubscription = Subscription.EMPTY;
this._positionSubscription = Subscription.EMPTY;
this._disposeOnNavigation = false;
this.viewportMargin = 0;
this.open = false;
this.disableClose = false;
this.hasBackdrop = false;
this.lockPosition = false;
this.flexibleDimensions = false;
this.growAfterOpen = false;
this.push = false;
this.backdropClick = new EventEmitter();
this.positionChange = new EventEmitter();
this.attach = new EventEmitter();
this.detach = new EventEmitter();
this.overlayKeydown = new EventEmitter();
this.overlayOutsideClick = new EventEmitter();
this._templatePortal = new TemplatePortal(templateRef, viewContainerRef);
this._scrollStrategyFactory = scrollStrategyFactory;
this.scrollStrategy = this._scrollStrategyFactory();
}
/** The associated overlay reference. */
get overlayRef() {
return this._overlayRef;
}
/** The element's layout direction. */
get dir() {
return this._dir ? this._dir.value : "ltr";
}
ngOnDestroy() {
this._attachSubscription.unsubscribe();
this._detachSubscription.unsubscribe();
this._backdropSubscription.unsubscribe();
this._positionSubscription.unsubscribe();
if (this._overlayRef) {
this._overlayRef.dispose();
}
}
ngOnChanges(changes) {
if (this._position) {
this._updatePositionStrategy(this._position);
this._overlayRef.updateSize({
width: this.width,
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();
}
}
/** Creates an overlay */
_createOverlay() {
if (!this.positions || !this.positions.length) {
this.positions = defaultPositionList;
}
const overlayRef = this._overlayRef = this._overlay.create(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) => {
this.overlayOutsideClick.next(event);
});
}
/** Builds the overlay config based on the directive's inputs */
_buildConfig() {
const positionStrategy = this._position = this.positionStrategy || this._createPositionStrategy();
const overlayConfig = new OverlayConfig({
direction: this._dir,
positionStrategy,
scrollStrategy: this.scrollStrategy,
hasBackdrop: this.hasBackdrop,
disposeOnNavigation: this.disposeOnNavigation
});
if (this.width || this.width === 0) {
overlayConfig.width = this.width;
}
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;
}
/** Updates the state of a position strategy, based on the values of the directive inputs. */
_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 || void 0
}));
return positionStrategy.setOrigin(this._getFlexibleConnectedPositionStrategyOrigin()).withPositions(positions).withFlexibleDimensions(this.flexibleDimensions).withPush(this.push).withGrowAfterOpen(this.growAfterOpen).withViewportMargin(this.viewportMargin).withLockedPosition(this.lockPosition).withTransformOriginOn(this.transformOriginSelector);
}
/** Returns the position strategy of the overlay to be set on the overlay config */
_createPositionStrategy() {
const strategy = this._overlay.position().flexibleConnectedTo(this._getFlexibleConnectedPositionStrategyOrigin());
this._updatePositionStrategy(strategy);
return strategy;
}
_getFlexibleConnectedPositionStrategyOrigin() {
if (this.origin instanceof CdkOverlayOrigin) {
return this.origin.elementRef;
} else {
return this.origin;
}
}
/** Attaches the overlay and subscribes to backdrop clicks if backdrop exists */
_attachOverlay() {
if (!this._overlayRef) {
this._createOverlay();
} else {
this._overlayRef.getConfig().hasBackdrop = this.hasBackdrop;
}
if (!this._overlayRef.hasAttached()) {
this._overlayRef.attach(this._templatePortal);
}
if (this.hasBackdrop) {
this._backdropSubscription = this._overlayRef.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.positionChange.emit(position);
if (this.positionChange.observers.length === 0) {
this._positionSubscription.unsubscribe();
}
});
}
}
/** Detaches the overlay and unsubscribes to backdrop clicks if backdrop exists */
_detachOverlay() {
if (this._overlayRef) {
this._overlayRef.detach();
}
this._backdropSubscription.unsubscribe();
this._positionSubscription.unsubscribe();
}
};
_CdkConnectedOverlay.ɵfac = function CdkConnectedOverlay_Factory(t) {
return new (t || _CdkConnectedOverlay)(ɵɵdirectiveInject(Overlay), ɵɵdirectiveInject(TemplateRef), ɵɵdirectiveInject(ViewContainerRef), ɵɵdirectiveInject(CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY), ɵɵdirectiveInject(Directionality, 8));
};
_CdkConnectedOverlay.ɵdir = ɵɵdefineDirective({
type: _CdkConnectedOverlay,
selectors: [["", "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]
},
outputs: {
backdropClick: "backdropClick",
positionChange: "positionChange",
attach: "attach",
detach: "detach",
overlayKeydown: "overlayKeydown",
overlayOutsideClick: "overlayOutsideClick"
},
exportAs: ["cdkConnectedOverlay"],
standalone: true,
features: [ɵɵInputTransformsFeature, ɵɵNgOnChangesFeature]
});
var CdkConnectedOverlay = _CdkConnectedOverlay;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CdkConnectedOverlay, [{
type: Directive,
args: [{
selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]",
exportAs: "cdkConnectedOverlay",
standalone: true
}]
}], () => [{
type: Overlay
}, {
type: TemplateRef
}, {
type: ViewContainerRef
}, {
type: void 0,
decorators: [{
type: Inject,
args: [CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY]
}]
}, {
type: Directionality,
decorators: [{
type: Optional
}]
}], {
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
}]
}],
backdropClick: [{
type: Output
}],
positionChange: [{
type: Output
}],
attach: [{
type: Output
}],
detach: [{
type: Output
}],
overlayKeydown: [{
type: Output
}],
overlayOutsideClick: [{
type: Output
}]
});
})();
function CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY_PROVIDER_FACTORY(overlay) {
return () => overlay.scrollStrategies.reposition();
}
var CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY_PROVIDER = {
provide: CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY,
deps: [Overlay],
useFactory: CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY_PROVIDER_FACTORY
};
var _OverlayModule = class _OverlayModule {
};
_OverlayModule.ɵfac = function OverlayModule_Factory(t) {
return new (t || _OverlayModule)();
};
_OverlayModule.ɵmod = ɵɵdefineNgModule({
type: _OverlayModule,
imports: [BidiModule, PortalModule, ScrollingModule, CdkConnectedOverlay, CdkOverlayOrigin],
exports: [CdkConnectedOverlay, CdkOverlayOrigin, ScrollingModule]
});
_OverlayModule.ɵinj = ɵɵdefineInjector({
providers: [Overlay, CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY_PROVIDER],
imports: [BidiModule, PortalModule, ScrollingModule, ScrollingModule]
});
var OverlayModule = _OverlayModule;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(OverlayModule, [{
type: NgModule,
args: [{
imports: [BidiModule, PortalModule, ScrollingModule, CdkConnectedOverlay, CdkOverlayOrigin],
exports: [CdkConnectedOverlay, CdkOverlayOrigin, ScrollingModule],
providers: [Overlay, CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY_PROVIDER]
}]
}], null, null);
})();
var _FullscreenOverlayContainer = class _FullscreenOverlayContainer extends OverlayContainer {
constructor(_document, platform) {
super(_document, platform);
}
ngOnDestroy() {
super.ngOnDestroy();
if (this._fullScreenEventName && this._fullScreenListener) {
this._document.removeEventListener(this._fullScreenEventName, this._fullScreenListener);
}
}
_createContainer() {
super._createContainer();
this._adjustParentForFullscreenChange();
this._addFullscreenChangeListener(() => this._adjustParentForFullscreenChange());
}
_adjustParentForFullscreenChange() {
if (!this._containerElement) {
return;
}
const fullscreenElement = this.getFullscreenElement();
const parent = fullscreenElement || this._document.body;
parent.appendChild(this._containerElement);
}
_addFullscreenChangeListener(fn) {
const eventName = this._getEventName();
if (eventName) {
if (this._fullScreenListener) {
this._document.removeEventListener(eventName, this._fullScreenListener);
}
this._document.addEventListener(eventName, fn);
this._fullScreenListener = fn;
}
}
_getEventName() {
if (!this._fullScreenEventName) {
const _document = this._document;
if (_document.fullscreenEnabled) {
this._fullScreenEventName = "fullscreenchange";
} else if (_document.webkitFullscreenEnabled) {
this._fullScreenEventName = "webkitfullscreenchange";
} else if (_document.mozFullScreenEnabled) {
this._fullScreenEventName = "mozfullscreenchange";
} else if (_document.msFullscreenEnabled) {
this._fullScreenEventName = "MSFullscreenChange";
}
}
return this._fullScreenEventName;
}
/**
* When the page is put into fullscreen mode, a specific element is specified.
* Only that element and its children are visible when in fullscreen mode.
*/
getFullscreenElement() {
const _document = this._document;
return _document.fullscreenElement || _document.webkitFullscreenElement || _document.mozFullScreenElement || _document.msFullscreenElement || null;
}
};
_FullscreenOverlayContainer.ɵfac = function FullscreenOverlayContainer_Factory(t) {
return new (t || _FullscreenOverlayContainer)(ɵɵinject(DOCUMENT), ɵɵinject(Platform));
};
_FullscreenOverlayContainer.ɵprov = ɵɵdefineInjectable({
token: _FullscreenOverlayContainer,
factory: _FullscreenOverlayContainer.ɵfac,
providedIn: "root"
});
var FullscreenOverlayContainer = _FullscreenOverlayContainer;
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(FullscreenOverlayContainer, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: void 0,
decorators: [{
type: Inject,
args: [DOCUMENT]
}]
}, {
type: Platform
}], null);
})();
export {
ViewportRuler,
ComponentPortal,
TemplatePortal,
CdkPortalOutlet,
PortalModule,
OverlayConfig,
ConnectionPositionPair,
OverlayKeyboardDispatcher,
Overlay,
CdkOverlayOrigin,
CdkConnectedOverlay,
OverlayModule
};
//# sourceMappingURL=chunk-6U656R5M.js.map