diff --git a/goldens/material/autocomplete/index.api.md b/goldens/material/autocomplete/index.api.md index 4bae890c74cd..734b7b16abcc 100644 --- a/goldens/material/autocomplete/index.api.md +++ b/goldens/material/autocomplete/index.api.md @@ -23,7 +23,6 @@ import { Observable } from 'rxjs'; import { OnChanges } from '@angular/core'; import { OnDestroy } from '@angular/core'; import { OnInit } from '@angular/core'; -import { Overlay } from '@angular/cdk/overlay'; import { QueryList } from '@angular/core'; import { ScrollStrategy } from '@angular/cdk/overlay'; import { SimpleChanges } from '@angular/core'; @@ -43,12 +42,12 @@ export function MAT_AUTOCOMPLETE_DEFAULT_OPTIONS_FACTORY(): MatAutocompleteDefau export const MAT_AUTOCOMPLETE_SCROLL_STRATEGY: InjectionToken<() => ScrollStrategy>; // @public @deprecated -export function MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy; +export function MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY(_overlay: unknown): () => ScrollStrategy; // @public @deprecated export const MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY_PROVIDER: { provide: InjectionToken<() => ScrollStrategy>; - deps: (typeof Overlay)[]; + deps: any[]; useFactory: typeof MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY; }; diff --git a/goldens/material/datepicker/index.api.md b/goldens/material/datepicker/index.api.md index df896702802f..c1403ede28db 100644 --- a/goldens/material/datepicker/index.api.md +++ b/goldens/material/datepicker/index.api.md @@ -33,7 +33,6 @@ import { Observable } from 'rxjs'; import { OnChanges } from '@angular/core'; import { OnDestroy } from '@angular/core'; import { OnInit } from '@angular/core'; -import { Overlay } from '@angular/cdk/overlay'; import { Portal } from '@angular/cdk/portal'; import { ScrollStrategy } from '@angular/cdk/overlay'; import { SimpleChanges } from '@angular/core'; @@ -94,12 +93,12 @@ export const MAT_DATE_RANGE_SELECTION_STRATEGY: InjectionToken ScrollStrategy>; // @public @deprecated -export function MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy; +export function MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY(_overlay: unknown): () => ScrollStrategy; // @public @deprecated export const MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER: { provide: InjectionToken<() => ScrollStrategy>; - deps: (typeof Overlay)[]; + deps: any[]; useFactory: typeof MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY; }; diff --git a/goldens/material/menu/index.api.md b/goldens/material/menu/index.api.md index 8662110179c9..f791dc2d3cde 100644 --- a/goldens/material/menu/index.api.md +++ b/goldens/material/menu/index.api.md @@ -18,7 +18,6 @@ import { InjectionToken } from '@angular/core'; import { Observable } from 'rxjs'; import { OnDestroy } from '@angular/core'; import { OnInit } from '@angular/core'; -import { Overlay } from '@angular/cdk/overlay'; import { QueryList } from '@angular/core'; import { ScrollStrategy } from '@angular/cdk/overlay'; import { Subject } from 'rxjs'; @@ -42,7 +41,7 @@ export const MAT_MENU_SCROLL_STRATEGY: InjectionToken<() => ScrollStrategy>; // @public @deprecated export const MAT_MENU_SCROLL_STRATEGY_FACTORY_PROVIDER: { provide: InjectionToken<() => ScrollStrategy>; - deps: (typeof Overlay)[]; + deps: any[]; useFactory: typeof MAT_MENU_SCROLL_STRATEGY_FACTORY; }; diff --git a/goldens/material/select/index.api.md b/goldens/material/select/index.api.md index 084750dd1a86..2f5bc1a33b51 100644 --- a/goldens/material/select/index.api.md +++ b/goldens/material/select/index.api.md @@ -35,7 +35,6 @@ import { Observable } from 'rxjs'; import { OnChanges } from '@angular/core'; import { OnDestroy } from '@angular/core'; import { OnInit } from '@angular/core'; -import { Overlay } from '@angular/cdk/overlay'; import { QueryList } from '@angular/core'; import { ScrollStrategy } from '@angular/cdk/overlay'; import { SelectionModel } from '@angular/cdk/collections'; @@ -52,12 +51,12 @@ export const MAT_SELECT_SCROLL_STRATEGY: InjectionToken<() => ScrollStrategy>; // @public @deprecated export const MAT_SELECT_SCROLL_STRATEGY_PROVIDER: { provide: InjectionToken<() => ScrollStrategy>; - deps: (typeof Overlay)[]; + deps: any[]; useFactory: typeof MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY; }; // @public @deprecated -export function MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY(overlay: Overlay): () => ScrollStrategy; +export function MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY(_overlay: unknown): () => ScrollStrategy; // @public export const MAT_SELECT_TRIGGER: InjectionToken; diff --git a/goldens/material/tooltip/index.api.md b/goldens/material/tooltip/index.api.md index 179ae42d6ffa..198a0989409f 100644 --- a/goldens/material/tooltip/index.api.md +++ b/goldens/material/tooltip/index.api.md @@ -19,7 +19,6 @@ import { NumberInput } from '@angular/cdk/coercion'; import { Observable } from 'rxjs'; import { OnDestroy } from '@angular/core'; import { OriginConnectionPosition } from '@angular/cdk/overlay'; -import { Overlay } from '@angular/cdk/overlay'; import { OverlayConnectionPosition } from '@angular/cdk/overlay'; import { OverlayRef } from '@angular/cdk/overlay'; import { ScrollStrategy } from '@angular/cdk/overlay'; @@ -37,12 +36,12 @@ export function MAT_TOOLTIP_DEFAULT_OPTIONS_FACTORY(): MatTooltipDefaultOptions; export const MAT_TOOLTIP_SCROLL_STRATEGY: InjectionToken<() => ScrollStrategy>; // @public @deprecated -export function MAT_TOOLTIP_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy; +export function MAT_TOOLTIP_SCROLL_STRATEGY_FACTORY(_overlay: unknown): () => ScrollStrategy; // @public @deprecated export const MAT_TOOLTIP_SCROLL_STRATEGY_FACTORY_PROVIDER: { provide: InjectionToken<() => ScrollStrategy>; - deps: (typeof Overlay)[]; + deps: any[]; useFactory: typeof MAT_TOOLTIP_SCROLL_STRATEGY_FACTORY; }; diff --git a/src/cdk-experimental/column-resize/resizable.ts b/src/cdk-experimental/column-resize/resizable.ts index 8e2726a6f9f1..d713035213a2 100644 --- a/src/cdk-experimental/column-resize/resizable.ts +++ b/src/cdk-experimental/column-resize/resizable.ts @@ -23,7 +23,12 @@ import { } from '@angular/core'; import {Directionality} from '@angular/cdk/bidi'; import {ComponentPortal} from '@angular/cdk/portal'; -import {Overlay, OverlayRef} from '@angular/cdk/overlay'; +import { + createFlexibleConnectedPositionStrategy, + createOverlayRef, + createRepositionScrollStrategy, + OverlayRef, +} from '@angular/cdk/overlay'; import {CdkColumnDef, _CoalescedStyleScheduler} from '@angular/cdk/table'; import {merge, Subject} from 'rxjs'; import {distinctUntilChanged, filter, take, takeUntil} from 'rxjs/operators'; @@ -64,7 +69,6 @@ export abstract class Resizable protected abstract readonly eventDispatcher: HeaderRowEventDispatcher; protected abstract readonly injector: Injector; protected abstract readonly ngZone: NgZone; - protected abstract readonly overlay: Overlay; protected abstract readonly resizeNotifier: ColumnResizeNotifierSource; protected abstract readonly resizeStrategy: ResizeStrategy; protected abstract readonly styleScheduler: _CoalescedStyleScheduler; @@ -72,6 +76,7 @@ export abstract class Resizable protected abstract readonly changeDetectorRef: ChangeDetectorRef; protected readonly columnSizeStore = inject(ColumnSizeStore, {optional: true}); + private _injector = inject(Injector); private _viewInitialized = false; private _isDestroyed = false; @@ -146,9 +151,10 @@ export abstract class Resizable // over both cells and extending it down the table as needed. const isRtl = this.directionality.value === 'rtl'; - const positionStrategy = this.overlay - .position() - .flexibleConnectedTo(this.elementRef.nativeElement!) + const positionStrategy = createFlexibleConnectedPositionStrategy( + this._injector, + this.elementRef.nativeElement!, + ) .withFlexibleDimensions(false) .withGrowAfterOpen(false) .withPush(false) @@ -162,12 +168,12 @@ export abstract class Resizable }, ]); - return this.overlay.create({ + return createOverlayRef(this._injector, { // Always position the overlay based on left-indexed coordinates. direction: 'ltr', disposeOnNavigation: true, positionStrategy, - scrollStrategy: this.overlay.scrollStrategies.reposition(), + scrollStrategy: createRepositionScrollStrategy(this._injector), width: '16px', }); } diff --git a/src/cdk-experimental/combobox/combobox.ts b/src/cdk-experimental/combobox/combobox.ts index e934a0521c47..5044d08c802a 100644 --- a/src/cdk-experimental/combobox/combobox.ts +++ b/src/cdk-experimental/combobox/combobox.ts @@ -10,8 +10,10 @@ import {BooleanInput, coerceArray, coerceBooleanProperty} from '@angular/cdk/coe import {DOWN_ARROW, ENTER, ESCAPE, TAB} from '@angular/cdk/keycodes'; import { ConnectedPosition, + createBlockScrollStrategy, + createFlexibleConnectedPositionStrategy, + createOverlayRef, FlexibleConnectedPositionStrategy, - Overlay, OverlayConfig, OverlayRef, } from '@angular/cdk/overlay'; @@ -64,7 +66,6 @@ export const CDK_COMBOBOX = new InjectionToken('CDK_COMBOBOX'); export class CdkCombobox implements OnDestroy { private readonly _tagName = inject(HOST_TAG_NAME); private readonly _elementRef = inject>(ElementRef); - private readonly _overlay = inject(Overlay); protected readonly _viewContainerRef = inject(ViewContainerRef); private readonly _injector = inject(Injector); private readonly _doc = inject(DOCUMENT); @@ -191,7 +192,8 @@ export class CdkCombobox implements OnDestroy { open() { if (!this.isOpen() && !this.disabled) { this.opened.next(); - this._overlayRef = this._overlayRef || this._overlay.create(this._getOverlayConfig()); + this._overlayRef = + this._overlayRef || createOverlayRef(this._injector, this._getOverlayConfig()); this._overlayRef.attach(this._getPanelContent()); this._changeDetectorRef.markForCheck(); if (!this._isTextTrigger()) { @@ -255,16 +257,15 @@ export class CdkCombobox implements OnDestroy { private _getOverlayConfig() { return new OverlayConfig({ positionStrategy: this._getOverlayPositionStrategy(), - scrollStrategy: this._overlay.scrollStrategies.block(), + scrollStrategy: createBlockScrollStrategy(this._injector), direction: this._directionality || undefined, }); } private _getOverlayPositionStrategy(): FlexibleConnectedPositionStrategy { - return this._overlay - .position() - .flexibleConnectedTo(this._elementRef) - .withPositions(this._getOverlayPositions()); + return createFlexibleConnectedPositionStrategy(this._injector, this._elementRef).withPositions( + this._getOverlayPositions(), + ); } private _getOverlayPositions(): ConnectedPosition[] { diff --git a/src/cdk-experimental/popover-edit/edit-services.ts b/src/cdk-experimental/popover-edit/edit-services.ts index 1be53cdf0efa..74454a4a0f56 100644 --- a/src/cdk-experimental/popover-edit/edit-services.ts +++ b/src/cdk-experimental/popover-edit/edit-services.ts @@ -9,7 +9,6 @@ import {Injectable, NgZone, inject} from '@angular/core'; import {FocusTrapFactory} from '@angular/cdk/a11y'; import {Directionality} from '@angular/cdk/bidi'; -import {Overlay} from '@angular/cdk/overlay'; import {ScrollDispatcher, ViewportRuler} from '@angular/cdk/scrolling'; import {EditEventDispatcher} from './edit-event-dispatcher'; @@ -29,7 +28,6 @@ export class EditServices { readonly focusDispatcher = inject(FocusDispatcher); readonly focusTrapFactory = inject(FocusTrapFactory); readonly ngZone = inject(NgZone); - readonly overlay = inject(Overlay); readonly scrollDispatcher = inject(ScrollDispatcher); readonly viewportRuler = inject(ViewportRuler); } diff --git a/src/cdk-experimental/popover-edit/table-directives.ts b/src/cdk-experimental/popover-edit/table-directives.ts index 34130fa89c65..427fac7c2889 100644 --- a/src/cdk-experimental/popover-edit/table-directives.ts +++ b/src/cdk-experimental/popover-edit/table-directives.ts @@ -6,7 +6,14 @@ * found in the LICENSE file at https://angular.dev/license */ import {FocusTrap} from '@angular/cdk/a11y'; -import {OverlayRef, OverlaySizeConfig, PositionStrategy} from '@angular/cdk/overlay'; +import { + createFlexibleConnectedPositionStrategy, + createOverlayRef, + createRepositionScrollStrategy, + OverlayRef, + OverlaySizeConfig, + PositionStrategy, +} from '@angular/cdk/overlay'; import {TemplatePortal} from '@angular/cdk/portal'; import { afterNextRender, @@ -15,6 +22,7 @@ import { ElementRef, EmbeddedViewRef, inject, + Injector, ListenerOptions, NgZone, OnDestroy, @@ -240,6 +248,7 @@ export class CdkPopoverEdit implements AfterViewInit, OnDestroy { protected readonly services = inject(EditServices); protected readonly elementRef = inject(ElementRef); protected readonly viewContainerRef = inject(ViewContainerRef); + private _injector = inject(Injector); /** The edit lens template shown over the cell on edit. */ template: TemplateRef | null = null; @@ -344,11 +353,11 @@ export class CdkPopoverEdit implements AfterViewInit, OnDestroy { } private _createEditOverlay(): void { - this.overlayRef = this.services.overlay.create({ + this.overlayRef = createOverlayRef(this._injector, { disposeOnNavigation: true, panelClass: this.panelClass(), positionStrategy: this._getPositionStrategy(), - scrollStrategy: this.services.overlay.scrollStrategies.reposition(), + scrollStrategy: createRepositionScrollStrategy(this._injector), direction: this.services.directionality, }); @@ -402,9 +411,7 @@ export class CdkPopoverEdit implements AfterViewInit, OnDestroy { private _getPositionStrategy(): PositionStrategy { const cells = this._getOverlayCells(); - return this.services.overlay - .position() - .flexibleConnectedTo(cells[0]) + return createFlexibleConnectedPositionStrategy(this._injector, cells[0]) .withGrowAfterOpen() .withPush() .withViewportMargin(16) diff --git a/src/cdk/a11y/live-announcer/live-announcer.spec.ts b/src/cdk/a11y/live-announcer/live-announcer.spec.ts index c92882f3a570..7c9195fbd6a7 100644 --- a/src/cdk/a11y/live-announcer/live-announcer.spec.ts +++ b/src/cdk/a11y/live-announcer/live-announcer.spec.ts @@ -1,7 +1,6 @@ import {MutationObserverFactory} from '../../observers'; -import {Overlay} from '../../overlay'; import {ComponentPortal} from '../../portal'; -import {Component, inject} from '@angular/core'; +import {Component, inject, Injector} from '@angular/core'; import {ComponentFixture, TestBed, fakeAsync, flush, tick} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {A11yModule} from '../index'; @@ -11,10 +10,10 @@ import { LIVE_ANNOUNCER_ELEMENT_TOKEN, LiveAnnouncerDefaultOptions, } from './live-announcer-tokens'; +import {createOverlayRef} from '@angular/cdk/overlay'; describe('LiveAnnouncer', () => { let announcer: LiveAnnouncer; - let overlay: Overlay; let ariaLiveElement: Element; let fixture: ComponentFixture; @@ -26,7 +25,6 @@ describe('LiveAnnouncer', () => { ); beforeEach(fakeAsync(() => { - overlay = TestBed.inject(Overlay); announcer = TestBed.inject(LiveAnnouncer); ariaLiveElement = getLiveElement(); fixture = TestBed.createComponent(TestApp); @@ -172,7 +170,7 @@ describe('LiveAnnouncer', () => { it('should add aria-owns to open aria-modal elements', fakeAsync(() => { const portal = new ComponentPortal(TestModal); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(TestBed.inject(Injector)); const componentRef = overlayRef.attach(portal); const modal = componentRef.location.nativeElement; fixture.detectChanges(); @@ -192,7 +190,7 @@ describe('LiveAnnouncer', () => { it('should expand aria-owns of open aria-modal elements', fakeAsync(() => { const portal = new ComponentPortal(TestModal); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(TestBed.inject(Injector)); const componentRef = overlayRef.attach(portal); const modal = componentRef.location.nativeElement; fixture.detectChanges(); diff --git a/src/cdk/dialog/dialog-injectors.ts b/src/cdk/dialog/dialog-injectors.ts index 9d1cc780f395..69ce566b4410 100644 --- a/src/cdk/dialog/dialog-injectors.ts +++ b/src/cdk/dialog/dialog-injectors.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.dev/license */ -import {InjectionToken, inject} from '@angular/core'; -import {Overlay, ScrollStrategy} from '../overlay'; +import {InjectionToken, Injector, inject} from '@angular/core'; +import {createBlockScrollStrategy, ScrollStrategy} from '../overlay'; import {DialogConfig} from './dialog-config'; /** Injection token for the Dialog's ScrollStrategy. */ @@ -16,8 +16,8 @@ export const DIALOG_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrategy>( { providedIn: 'root', factory: () => { - const overlay = inject(Overlay); - return () => overlay.scrollStrategies.block(); + const injector = inject(Injector); + return () => createBlockScrollStrategy(injector); }, }, ); diff --git a/src/cdk/dialog/dialog.spec.ts b/src/cdk/dialog/dialog.spec.ts index ef57e478b505..71383634c35b 100644 --- a/src/cdk/dialog/dialog.spec.ts +++ b/src/cdk/dialog/dialog.spec.ts @@ -1,6 +1,11 @@ import {Directionality} from '../bidi'; import {A, ESCAPE} from '../keycodes'; -import {Overlay, OverlayContainer, ScrollDispatcher} from '../overlay'; +import { + createCloseScrollStrategy, + createGlobalPositionStrategy, + OverlayContainer, + ScrollDispatcher, +} from '../overlay'; import {_supportsShadowDom} from '../platform'; import {createKeyboardEvent, dispatchEvent, dispatchKeyboardEvent} from '../testing/private'; import {Location} from '@angular/common'; @@ -37,7 +42,6 @@ describe('Dialog', () => { let testViewContainerRef: ViewContainerRef; let viewContainerFixture: ComponentFixture; let mockLocation: SpyLocation; - let overlay: Overlay; let scrolledSubject = new Subject(); beforeEach(fakeAsync(() => { @@ -66,7 +70,6 @@ describe('Dialog', () => { dialog = TestBed.inject(Dialog); mockLocation = TestBed.inject(Location) as SpyLocation; - overlay = TestBed.inject(Overlay); overlayContainerElement = TestBed.inject(OverlayContainer).getContainerElement(); viewContainerFixture = TestBed.createComponent(ComponentWithChildViewContainer); @@ -452,7 +455,7 @@ describe('Dialog', () => { it('should be able to customize the position strategy', () => { dialog.open(PizzaMsg, { - positionStrategy: overlay.position().global().top('100px'), + positionStrategy: createGlobalPositionStrategy(TestBed.inject(Injector)).top('100px'), }); viewContainerFixture.detectChanges(); @@ -555,12 +558,13 @@ describe('Dialog', () => { it('should close the dialog when detached externally', fakeAsync(() => { const closeSpy = jasmine.createSpy('closed'); + const injector = TestBed.inject(Injector); dialog - .open(PizzaMsg, {scrollStrategy: overlay.scrollStrategies.close()}) + .open(PizzaMsg, {scrollStrategy: createCloseScrollStrategy(injector)}) .closed.subscribe(closeSpy); viewContainerFixture.detectChanges(); dialog - .open(PizzaMsg, {scrollStrategy: overlay.scrollStrategies.close()}) + .open(PizzaMsg, {scrollStrategy: createCloseScrollStrategy(injector)}) .closed.subscribe(closeSpy); viewContainerFixture.detectChanges(); diff --git a/src/cdk/dialog/dialog.ts b/src/cdk/dialog/dialog.ts index 9149b11d8060..5ff00f544073 100644 --- a/src/cdk/dialog/dialog.ts +++ b/src/cdk/dialog/dialog.ts @@ -22,7 +22,14 @@ import {Observable, Subject, defer} from 'rxjs'; import {startWith} from 'rxjs/operators'; import {_IdGenerator} from '../a11y'; import {Direction, Directionality} from '../bidi'; -import {ComponentType, Overlay, OverlayConfig, OverlayContainer, OverlayRef} from '../overlay'; +import { + ComponentType, + createGlobalPositionStrategy, + createOverlayRef, + OverlayConfig, + OverlayContainer, + OverlayRef, +} from '../overlay'; import {BasePortalOutlet, ComponentPortal, TemplatePortal} from '../portal'; import {DialogConfig} from './dialog-config'; import {DialogRef} from './dialog-ref'; @@ -47,7 +54,6 @@ function getDirectionality(value: Direction): Directionality { @Injectable({providedIn: 'root'}) export class Dialog implements OnDestroy { - private _overlay = inject(Overlay); private _injector = inject(Injector); private _defaultOptions = inject(DEFAULT_DIALOG_CONFIG, {optional: true}); private _parentDialog = inject(Dialog, {optional: true, skipSelf: true}); @@ -131,7 +137,7 @@ export class Dialog implements OnDestroy { } const overlayConfig = this._getOverlayConfig(config); - const overlayRef = this._overlay.create(overlayConfig); + const overlayRef = createOverlayRef(this._injector, overlayConfig); const dialogRef = new DialogRef(overlayRef, config); const dialogContainer = this._attachContainer(overlayRef, dialogRef, config); @@ -195,7 +201,7 @@ export class Dialog implements OnDestroy { const state = new OverlayConfig({ positionStrategy: config.positionStrategy || - this._overlay.position().global().centerHorizontally().centerVertically(), + createGlobalPositionStrategy(this._injector).centerHorizontally().centerVertically(), scrollStrategy: config.scrollStrategy || this._scrollStrategy(), panelClass: config.panelClass, hasBackdrop: config.hasBackdrop, diff --git a/src/cdk/menu/context-menu-trigger.ts b/src/cdk/menu/context-menu-trigger.ts index 0554fffb9cd7..2c2640d4b2c1 100644 --- a/src/cdk/menu/context-menu-trigger.ts +++ b/src/cdk/menu/context-menu-trigger.ts @@ -12,13 +12,15 @@ import { Directive, inject, Injectable, + Injector, Input, OnDestroy, } from '@angular/core'; import {Directionality} from '../bidi'; import { + createFlexibleConnectedPositionStrategy, + createOverlayRef, FlexibleConnectedPositionStrategy, - Overlay, OverlayConfig, STANDARD_DROPDOWN_BELOW_POSITIONS, } from '../overlay'; @@ -81,15 +83,9 @@ export type ContextMenuCoordinates = {x: number; y: number}; ], }) export class CdkContextMenuTrigger extends CdkMenuTriggerBase implements OnDestroy { - /** The CDK overlay service. */ - private readonly _overlay = inject(Overlay); - - /** The directionality of the page. */ + private readonly _injector = inject(Injector); private readonly _directionality = inject(Directionality, {optional: true}); - - /** The app's context menu tracking registry */ private readonly _contextMenuTracker = inject(ContextMenuTracker); - private readonly _changeDetectorRef = inject(ChangeDetectorRef); /** Whether the context menu is disabled. */ @@ -161,9 +157,7 @@ export class CdkContextMenuTrigger extends CdkMenuTriggerBase implements OnDestr private _getOverlayPositionStrategy( coordinates: ContextMenuCoordinates, ): FlexibleConnectedPositionStrategy { - return this._overlay - .position() - .flexibleConnectedTo(coordinates) + return createFlexibleConnectedPositionStrategy(this._injector, coordinates) .withLockedPosition() .withGrowAfterOpen() .withPositions(this.menuPosition ?? CONTEXT_MENU_POSITIONS); @@ -244,7 +238,7 @@ export class CdkContextMenuTrigger extends CdkMenuTriggerBase implements OnDestr ).setOrigin(coordinates); this.overlayRef.updatePosition(); } else { - this.overlayRef = this._overlay.create(this._getOverlayConfig(coordinates)); + this.overlayRef = createOverlayRef(this._injector, this._getOverlayConfig(coordinates)); } this.overlayRef.attach(this.getMenuContentPortal()); diff --git a/src/cdk/menu/menu-trigger-base.ts b/src/cdk/menu/menu-trigger-base.ts index c800e0c8bb52..d0ba4728920a 100644 --- a/src/cdk/menu/menu-trigger-base.ts +++ b/src/cdk/menu/menu-trigger-base.ts @@ -18,7 +18,12 @@ import { } from '@angular/core'; import {Menu} from './menu-interface'; import {MENU_STACK, MenuStack} from './menu-stack'; -import {ConnectedPosition, Overlay, OverlayRef, ScrollStrategy} from '../overlay'; +import { + ConnectedPosition, + createRepositionScrollStrategy, + OverlayRef, + ScrollStrategy, +} from '../overlay'; import {TemplatePortal} from '../portal'; import {merge, Subject} from 'rxjs'; @@ -31,8 +36,8 @@ export const MENU_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrategy>( { providedIn: 'root', factory: () => { - const overlay = inject(Overlay); - return () => overlay.scrollStrategies.reposition(); + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector); }, }, ); diff --git a/src/cdk/menu/menu-trigger.ts b/src/cdk/menu/menu-trigger.ts index b6438b58188c..6fa7c834fe74 100644 --- a/src/cdk/menu/menu-trigger.ts +++ b/src/cdk/menu/menu-trigger.ts @@ -11,6 +11,7 @@ import { Directive, ElementRef, inject, + Injector, NgZone, OnChanges, OnDestroy, @@ -21,8 +22,9 @@ import {InputModalityDetector} from '../a11y'; import {Directionality} from '../bidi'; import { ConnectedPosition, + createFlexibleConnectedPositionStrategy, + createOverlayRef, FlexibleConnectedPositionStrategy, - Overlay, OverlayConfig, STANDARD_DROPDOWN_ADJACENT_POSITIONS, STANDARD_DROPDOWN_BELOW_POSITIONS, @@ -76,12 +78,12 @@ import {eventDispatchesNativeClick} from './event-detection'; }) export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnChanges, OnDestroy { private readonly _elementRef: ElementRef = inject(ElementRef); - private readonly _overlay = inject(Overlay); private readonly _ngZone = inject(NgZone); private readonly _changeDetectorRef = inject(ChangeDetectorRef); private readonly _inputModalityDetector = inject(InputModalityDetector); private readonly _directionality = inject(Directionality, {optional: true}); private readonly _renderer = inject(Renderer2); + private readonly _injector = inject(Injector); private _cleanupMouseenter: () => void; /** The parent menu this trigger belongs to. */ @@ -110,7 +112,8 @@ export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnChanges, OnD if (!this.isOpen() && this.menuTemplateRef != null) { this.opened.next(); - this.overlayRef = this.overlayRef || this._overlay.create(this._getOverlayConfig()); + this.overlayRef = + this.overlayRef || createOverlayRef(this._injector, this._getOverlayConfig()); this.overlayRef.attach(this.getMenuContentPortal()); this._changeDetectorRef.markForCheck(); this._subscribeToOutsideClicks(); @@ -272,9 +275,7 @@ export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnChanges, OnD /** Build the position strategy for the overlay which specifies where to place the menu. */ private _getOverlayPositionStrategy(): FlexibleConnectedPositionStrategy { - return this._overlay - .position() - .flexibleConnectedTo(this._elementRef) + return createFlexibleConnectedPositionStrategy(this._injector, this._elementRef) .withLockedPosition() .withFlexibleDimensions(false) .withPositions(this._getOverlayPositions()); diff --git a/src/cdk/overlay/dispatchers/overlay-keyboard-dispatcher.spec.ts b/src/cdk/overlay/dispatchers/overlay-keyboard-dispatcher.spec.ts index 58de3a09b69d..8d4d378a4f02 100644 --- a/src/cdk/overlay/dispatchers/overlay-keyboard-dispatcher.spec.ts +++ b/src/cdk/overlay/dispatchers/overlay-keyboard-dispatcher.spec.ts @@ -1,26 +1,25 @@ import {ESCAPE} from '../../keycodes'; import {ComponentPortal} from '../../portal'; -import {ApplicationRef, Component} from '@angular/core'; +import {ApplicationRef, Component, Injector} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {dispatchKeyboardEvent} from '../../testing/private'; -import {Overlay, OverlayModule} from '../index'; +import {createOverlayRef} from '../index'; import {OverlayKeyboardDispatcher} from './overlay-keyboard-dispatcher'; describe('OverlayKeyboardDispatcher', () => { let appRef: ApplicationRef; let keyboardDispatcher: OverlayKeyboardDispatcher; - let overlay: Overlay; + let injector: Injector; beforeEach(() => { - TestBed.configureTestingModule({imports: [OverlayModule, TestComponent]}); appRef = TestBed.inject(ApplicationRef); keyboardDispatcher = TestBed.inject(OverlayKeyboardDispatcher); - overlay = TestBed.inject(Overlay); + injector = TestBed.inject(Injector); }); it('should track overlays in order as they are attached and detached', () => { - const overlayOne = overlay.create(); - const overlayTwo = overlay.create(); + const overlayOne = createOverlayRef(injector); + const overlayTwo = createOverlayRef(injector); // Attach overlays keyboardDispatcher.add(overlayOne); @@ -49,8 +48,8 @@ describe('OverlayKeyboardDispatcher', () => { }); it('should dispatch body keyboard events to the most recently attached overlay', () => { - const overlayOne = overlay.create(); - const overlayTwo = overlay.create(); + const overlayOne = createOverlayRef(injector); + const overlayTwo = createOverlayRef(injector); const overlayOneSpy = jasmine.createSpy('overlayOne keyboard event spy'); const overlayTwoSpy = jasmine.createSpy('overlayTwo keyboard event spy'); @@ -69,7 +68,7 @@ describe('OverlayKeyboardDispatcher', () => { }); it('should not dispatch keyboard events when propagation is stopped', () => { - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); const spy = jasmine.createSpy('keyboard event spy'); const button = document.createElement('button'); @@ -85,7 +84,7 @@ describe('OverlayKeyboardDispatcher', () => { }); it('should complete the keydown stream on dispose', () => { - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); const completeSpy = jasmine.createSpy('keydown complete spy'); overlayRef.keydownEvents().subscribe({complete: completeSpy}); @@ -96,7 +95,7 @@ describe('OverlayKeyboardDispatcher', () => { }); it('should stop emitting events to detached overlays', () => { - const instance = overlay.create(); + const instance = createOverlayRef(injector); const spy = jasmine.createSpy('keyboard event spy'); instance.attach(new ComponentPortal(TestComponent)); @@ -112,7 +111,7 @@ describe('OverlayKeyboardDispatcher', () => { }); it('should stop emitting events to disposed overlays', () => { - const instance = overlay.create(); + const instance = createOverlayRef(injector); const spy = jasmine.createSpy('keyboard event spy'); instance.attach(new ComponentPortal(TestComponent)); @@ -128,7 +127,7 @@ describe('OverlayKeyboardDispatcher', () => { }); it('should dispose of the global keyboard event handler correctly', () => { - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); const body = document.body; spyOn(body, 'addEventListener'); spyOn(body, 'removeEventListener'); @@ -145,8 +144,8 @@ describe('OverlayKeyboardDispatcher', () => { }); it('should skip overlays that do not have keydown event subscriptions', () => { - const overlayOne = overlay.create(); - const overlayTwo = overlay.create(); + const overlayOne = createOverlayRef(injector); + const overlayTwo = createOverlayRef(injector); const overlayOneSpy = jasmine.createSpy('overlayOne keyboard event spy'); overlayOne.keydownEvents().subscribe(overlayOneSpy); @@ -159,8 +158,8 @@ describe('OverlayKeyboardDispatcher', () => { }); it('should not add the same overlay to the stack multiple times', () => { - const overlayOne = overlay.create(); - const overlayTwo = overlay.create(); + const overlayOne = createOverlayRef(injector); + const overlayTwo = createOverlayRef(injector); const overlayOneSpy = jasmine.createSpy('overlayOne keyboard event spy'); const overlayTwoSpy = jasmine.createSpy('overlayTwo keyboard event spy'); @@ -181,7 +180,7 @@ describe('OverlayKeyboardDispatcher', () => { it('should not run change detection if there are no `keydownEvents` observers', () => { spyOn(appRef, 'tick'); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); keyboardDispatcher.add(overlayRef); expect(appRef.tick).toHaveBeenCalledTimes(0); @@ -190,8 +189,5 @@ describe('OverlayKeyboardDispatcher', () => { }); }); -@Component({ - template: 'Hello', - imports: [OverlayModule], -}) +@Component({template: 'Hello'}) class TestComponent {} diff --git a/src/cdk/overlay/dispatchers/overlay-outside-click-dispatcher.spec.ts b/src/cdk/overlay/dispatchers/overlay-outside-click-dispatcher.spec.ts index c07dab73120a..b9ff3647b097 100644 --- a/src/cdk/overlay/dispatchers/overlay-outside-click-dispatcher.spec.ts +++ b/src/cdk/overlay/dispatchers/overlay-outside-click-dispatcher.spec.ts @@ -1,26 +1,25 @@ -import {ApplicationRef, Component} from '@angular/core'; +import {ApplicationRef, Component, Injector} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {filter, take} from 'rxjs/operators'; import {ComponentPortal} from '../../portal'; import {dispatchFakeEvent, dispatchMouseEvent} from '../../testing/private'; -import {Overlay, OverlayModule} from '../index'; +import {createOverlayRef} from '../index'; import {OverlayOutsideClickDispatcher} from './overlay-outside-click-dispatcher'; describe('OverlayOutsideClickDispatcher', () => { let appRef: ApplicationRef; let outsideClickDispatcher: OverlayOutsideClickDispatcher; - let overlay: Overlay; + let injector: Injector; beforeEach(() => { - TestBed.configureTestingModule({imports: [OverlayModule, TestComponent]}); appRef = TestBed.inject(ApplicationRef); outsideClickDispatcher = TestBed.inject(OverlayOutsideClickDispatcher); - overlay = TestBed.inject(Overlay); + injector = TestBed.inject(Injector); }); it('should track overlays in order as they are attached and detached', () => { - const overlayOne = overlay.create(); - const overlayTwo = overlay.create(); + const overlayOne = createOverlayRef(injector); + const overlayTwo = createOverlayRef(injector); outsideClickDispatcher.add(overlayOne); outsideClickDispatcher.add(overlayTwo); @@ -50,9 +49,9 @@ describe('OverlayOutsideClickDispatcher', () => { }); it('should dispatch mouse click events to the attached overlays', () => { - const overlayOne = overlay.create(); + const overlayOne = createOverlayRef(injector); overlayOne.attach(new ComponentPortal(TestComponent)); - const overlayTwo = overlay.create(); + const overlayTwo = createOverlayRef(injector); overlayTwo.attach(new ComponentPortal(TestComponent)); const overlayOneSpy = jasmine.createSpy('overlayOne mouse click event spy'); @@ -77,9 +76,9 @@ describe('OverlayOutsideClickDispatcher', () => { }); it('should dispatch auxiliary button click events to the attached overlays', () => { - const overlayOne = overlay.create(); + const overlayOne = createOverlayRef(injector); overlayOne.attach(new ComponentPortal(TestComponent)); - const overlayTwo = overlay.create(); + const overlayTwo = createOverlayRef(injector); overlayTwo.attach(new ComponentPortal(TestComponent)); const overlayOneSpy = jasmine.createSpy('overlayOne auxiliary click event spy'); @@ -104,7 +103,7 @@ describe('OverlayOutsideClickDispatcher', () => { }); it('should dispatch mouse click events to the attached overlays even when propagation is stopped', () => { - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(new ComponentPortal(TestComponent)); const spy = jasmine.createSpy('overlay mouse click event spy'); overlayRef.outsidePointerEvents().subscribe(spy); @@ -123,7 +122,7 @@ describe('OverlayOutsideClickDispatcher', () => { }); it('should dispose of the global click event handler correctly', () => { - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); const body = document.body; spyOn(body, 'addEventListener'); @@ -145,8 +144,8 @@ describe('OverlayOutsideClickDispatcher', () => { }); it('should not add the same overlay to the stack multiple times', () => { - const overlayOne = overlay.create(); - const overlayTwo = overlay.create(); + const overlayOne = createOverlayRef(injector); + const overlayTwo = createOverlayRef(injector); outsideClickDispatcher.add(overlayOne); outsideClickDispatcher.add(overlayTwo); @@ -160,7 +159,7 @@ describe('OverlayOutsideClickDispatcher', () => { it('should dispatch the click event when click is on an element outside the overlay', () => { const portal = new ComponentPortal(TestComponent); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(portal); const button = document.createElement('button'); document.body.appendChild(button); @@ -177,7 +176,7 @@ describe('OverlayOutsideClickDispatcher', () => { it('should not dispatch the click event when click is on an element inside the overlay', () => { const portal = new ComponentPortal(TestComponent); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(portal); const spy = jasmine.createSpy('overlay mouse click event spy'); @@ -194,7 +193,7 @@ describe('OverlayOutsideClickDispatcher', () => { 'released outside of it', () => { const portal = new ComponentPortal(TestComponent); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(portal); const context = document.createElement('div'); document.body.appendChild(context); @@ -216,7 +215,7 @@ describe('OverlayOutsideClickDispatcher', () => { 'released inside of it', () => { const portal = new ComponentPortal(TestComponent); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(portal); const spy = jasmine.createSpy('overlay mouse click event spy'); @@ -235,7 +234,7 @@ describe('OverlayOutsideClickDispatcher', () => { 'released outside of it', () => { const portal = new ComponentPortal(TestComponent); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(portal); const context = document.createElement('div'); document.body.appendChild(context); @@ -257,7 +256,7 @@ describe('OverlayOutsideClickDispatcher', () => { 'released inside of it', () => { const portal = new ComponentPortal(TestComponent); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(portal); const context = document.createElement('div'); document.body.appendChild(context); @@ -276,7 +275,7 @@ describe('OverlayOutsideClickDispatcher', () => { it('should dispatch an event when a context menu is triggered outside the overlay', () => { const portal = new ComponentPortal(TestComponent); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(portal); const context = document.createElement('div'); document.body.appendChild(context); @@ -293,7 +292,7 @@ describe('OverlayOutsideClickDispatcher', () => { it('should not dispatch an event when a context menu is triggered inside the overlay', () => { const portal = new ComponentPortal(TestComponent); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(portal); const spy = jasmine.createSpy('overlay contextmenu spy'); @@ -306,11 +305,11 @@ describe('OverlayOutsideClickDispatcher', () => { }); it('should not throw an error when closing out related components via the outsidePointerEvents emitter on background click', () => { - const firstOverlayRef = overlay.create(); + const firstOverlayRef = createOverlayRef(injector); firstOverlayRef.attach(new ComponentPortal(TestComponent)); - const secondOverlayRef = overlay.create(); + const secondOverlayRef = createOverlayRef(injector); secondOverlayRef.attach(new ComponentPortal(TestComponent)); - const thirdOverlayRef = overlay.create(); + const thirdOverlayRef = createOverlayRef(injector); thirdOverlayRef.attach(new ComponentPortal(TestComponent)); const spy = jasmine.createSpy('background click handler spy').and.callFake(() => { @@ -338,7 +337,7 @@ describe('OverlayOutsideClickDispatcher', () => { describe('change detection behavior', () => { it('should not run change detection if there is no portal attached to the overlay', () => { spyOn(appRef, 'tick'); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); outsideClickDispatcher.add(overlayRef); const context = document.createElement('div'); @@ -353,7 +352,7 @@ describe('OverlayOutsideClickDispatcher', () => { it('should not run change detection if the click was made outside the overlay but there are no `outsidePointerEvents` observers', () => { spyOn(appRef, 'tick'); const portal = new ComponentPortal(TestComponent); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(portal); outsideClickDispatcher.add(overlayRef); @@ -368,7 +367,7 @@ describe('OverlayOutsideClickDispatcher', () => { it('should not run change detection if the click was made inside the overlay and there are `outsidePointerEvents` observers', () => { spyOn(appRef, 'tick'); const portal = new ComponentPortal(TestComponent); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(portal); outsideClickDispatcher.add(overlayRef); @@ -399,7 +398,7 @@ describe('OverlayOutsideClickDispatcher', () => { renders = 0; expect(renders).toEqual(0); const portal = new ComponentPortal(TestComponent); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(portal); outsideClickDispatcher.add(overlayRef); @@ -421,8 +420,5 @@ describe('OverlayOutsideClickDispatcher', () => { }); }); -@Component({ - template: 'Hello', - imports: [OverlayModule], -}) +@Component({template: 'Hello'}) class TestComponent {} diff --git a/src/cdk/overlay/fullscreen-overlay-container.spec.ts b/src/cdk/overlay/fullscreen-overlay-container.spec.ts index 3a9942acc111..2fd2af0fc67a 100644 --- a/src/cdk/overlay/fullscreen-overlay-container.spec.ts +++ b/src/cdk/overlay/fullscreen-overlay-container.spec.ts @@ -1,11 +1,11 @@ import {waitForAsync, TestBed} from '@angular/core/testing'; -import {Component, NgModule, ViewChild, ViewContainerRef, inject, DOCUMENT} from '@angular/core'; -import {PortalModule, CdkPortal} from '../portal'; -import {Overlay, OverlayContainer, OverlayModule, FullscreenOverlayContainer} from './index'; +import {Component, ViewChild, ViewContainerRef, inject, DOCUMENT, Injector} from '@angular/core'; +import {CdkPortal} from '../portal'; +import {OverlayContainer, FullscreenOverlayContainer, createOverlayRef} from './index'; import {TemplatePortalDirective} from '../portal/portal-directives'; describe('FullscreenOverlayContainer', () => { - let overlay: Overlay; + let injector: Injector; let fullscreenListeners: Set; let fakeDocument: any; @@ -13,8 +13,11 @@ describe('FullscreenOverlayContainer', () => { fullscreenListeners = new Set(); TestBed.configureTestingModule({ - imports: [OverlayTestModule], providers: [ + { + provide: OverlayContainer, + useClass: FullscreenOverlayContainer, + }, { provide: DOCUMENT, useFactory: () => { @@ -56,14 +59,14 @@ describe('FullscreenOverlayContainer', () => { ], }); - overlay = TestBed.inject(Overlay); + injector = TestBed.inject(Injector); fakeDocument = TestBed.inject(DOCUMENT); })); it('should open an overlay inside a fullscreen element and move it to the body', () => { const fixture = TestBed.createComponent(TestComponentWithTemplatePortals); fixture.detectChanges(); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); const fullscreenElement = fakeDocument.fullscreenElement; overlayRef.attach(fixture.componentInstance.templatePortal); @@ -85,7 +88,7 @@ describe('FullscreenOverlayContainer', () => { const fixture = TestBed.createComponent(TestComponentWithTemplatePortals); fixture.detectChanges(); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(fixture.componentInstance.templatePortal); fixture.detectChanges(); @@ -104,7 +107,6 @@ describe('FullscreenOverlayContainer', () => { /** Test-bed component that contains a TempatePortal and an ElementRef. */ @Component({ template: `Cake`, - providers: [Overlay], imports: [TemplatePortalDirective], }) class TestComponentWithTemplatePortals { @@ -112,14 +114,3 @@ class TestComponentWithTemplatePortals { @ViewChild(CdkPortal) templatePortal: CdkPortal; } - -@NgModule({ - imports: [OverlayModule, PortalModule, TestComponentWithTemplatePortals], - providers: [ - { - provide: OverlayContainer, - useClass: FullscreenOverlayContainer, - }, - ], -}) -class OverlayTestModule {} diff --git a/src/cdk/overlay/overlay-container.spec.ts b/src/cdk/overlay/overlay-container.spec.ts index 698726afae0a..04af6b0691c7 100644 --- a/src/cdk/overlay/overlay-container.spec.ts +++ b/src/cdk/overlay/overlay-container.spec.ts @@ -1,25 +1,19 @@ import {waitForAsync, TestBed} from '@angular/core/testing'; -import {Component, NgModule, ViewChild, ViewContainerRef, inject} from '@angular/core'; -import {PortalModule, CdkPortal} from '../portal'; -import {Overlay, OverlayContainer, OverlayModule} from './index'; +import {Component, Injector, ViewChild, ViewContainerRef, inject} from '@angular/core'; +import {CdkPortal} from '../portal'; +import {createOverlayRef, OverlayContainer} from './index'; describe('OverlayContainer', () => { - let overlay: Overlay; let overlayContainer: OverlayContainer; beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [OverlayTestModule], - }); - - overlay = TestBed.inject(Overlay); overlayContainer = TestBed.inject(OverlayContainer); })); it('should remove the overlay container element from the DOM on destruction', () => { const fixture = TestBed.createComponent(TestComponentWithTemplatePortals); fixture.detectChanges(); - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(TestBed.inject(Injector)); overlayRef.attach(fixture.componentInstance.templatePortal); fixture.detectChanges(); @@ -88,7 +82,6 @@ describe('OverlayContainer', () => { /** Test-bed component that contains a TempatePortal and an ElementRef. */ @Component({ template: `Cake`, - providers: [Overlay], imports: [CdkPortal], }) class TestComponentWithTemplatePortals { @@ -96,8 +89,3 @@ class TestComponentWithTemplatePortals { @ViewChild(CdkPortal) templatePortal: CdkPortal; } - -@NgModule({ - imports: [OverlayModule, PortalModule, TestComponentWithTemplatePortals], -}) -class OverlayTestModule {} diff --git a/src/cdk/overlay/overlay-directives.spec.ts b/src/cdk/overlay/overlay-directives.spec.ts index a2b9675071e0..434b57500c77 100644 --- a/src/cdk/overlay/overlay-directives.spec.ts +++ b/src/cdk/overlay/overlay-directives.spec.ts @@ -1,6 +1,6 @@ import {Directionality} from '../bidi'; import {A, ESCAPE} from '../keycodes'; -import {Component, ElementRef, ViewChild} from '@angular/core'; +import {Component, ElementRef, Injector, ViewChild} from '@angular/core'; import {ComponentFixture, TestBed, fakeAsync, tick, waitForAsync} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {Subject} from 'rxjs'; @@ -8,7 +8,7 @@ import {createKeyboardEvent, dispatchEvent, dispatchKeyboardEvent} from '../test import { CdkConnectedOverlay, CdkOverlayOrigin, - Overlay, + createCloseScrollStrategy, OverlayModule, ScrollDispatcher, ScrollStrategy, @@ -19,12 +19,12 @@ import { ConnectionPositionPair, } from './position/connected-position'; import { + createFlexibleConnectedPositionStrategy, FlexibleConnectedPositionStrategy, FlexibleConnectedPositionStrategyOrigin, } from './position/flexible-connected-position-strategy'; describe('Overlay directives', () => { - let overlay: Overlay; let overlayContainerElement: HTMLElement; let fixture: ComponentFixture; let dir: {value: string}; @@ -44,7 +44,6 @@ describe('Overlay directives', () => { ], }); - overlay = TestBed.inject(Overlay); overlayContainerElement = TestBed.inject(OverlayContainer).getContainerElement(); fixture = TestBed.createComponent(ConnectedOverlayDirectiveTest); fixture.detectChanges(); @@ -70,9 +69,10 @@ describe('Overlay directives', () => { }); it('can change positionStrategy via input', () => { - const expectedPositionStrategy = overlay - .position() - .flexibleConnectedTo(document.body) + const expectedPositionStrategy = createFlexibleConnectedPositionStrategy( + TestBed.inject(Injector), + document.body, + ) .withFlexibleDimensions(true) .withPositions([{originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'top'}]); fixture.componentInstance.isOpen = true; @@ -705,7 +705,9 @@ describe('Overlay directives', () => { it('should emit when detached externally', () => { expect(fixture.componentInstance.detachHandler).not.toHaveBeenCalled(); - fixture.componentInstance.scrollStrategy = overlay.scrollStrategies.close(); + fixture.componentInstance.scrollStrategy = createCloseScrollStrategy( + TestBed.inject(Injector), + ); fixture.componentInstance.isOpen = true; fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); diff --git a/src/cdk/overlay/overlay-directives.ts b/src/cdk/overlay/overlay-directives.ts index af43e10c517e..48a1a1a57a95 100644 --- a/src/cdk/overlay/overlay-directives.ts +++ b/src/cdk/overlay/overlay-directives.ts @@ -14,6 +14,7 @@ import { ElementRef, EventEmitter, InjectionToken, + Injector, Input, NgZone, OnChanges, @@ -28,16 +29,21 @@ import { import {_getEventTarget} from '../platform'; import {Subscription} from 'rxjs'; import {takeWhile} from 'rxjs/operators'; -import {Overlay} from './overlay'; +import {createOverlayRef} from './overlay'; import {OverlayConfig} from './overlay-config'; import {OverlayRef} from './overlay-ref'; import {ConnectedOverlayPositionChange} from './position/connected-position'; import { ConnectedPosition, + createFlexibleConnectedPositionStrategy, FlexibleConnectedPositionStrategy, FlexibleConnectedPositionStrategyOrigin, } from './position/flexible-connected-position-strategy'; -import {RepositionScrollStrategy, ScrollStrategy} from './scroll/index'; +import { + createRepositionScrollStrategy, + RepositionScrollStrategy, + ScrollStrategy, +} from './scroll/index'; /** Default set of positions for the overlay. Follows the behavior of a dropdown. */ const defaultPositionList: ConnectedPosition[] = [ @@ -73,8 +79,8 @@ export const CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY = new InjectionToken<() => Sc { providedIn: 'root', factory: () => { - const overlay = inject(Overlay); - return () => overlay.scrollStrategies.reposition(); + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector); }, }, ); @@ -103,8 +109,8 @@ export class CdkOverlayOrigin { exportAs: 'cdkConnectedOverlay', }) export class CdkConnectedOverlay implements OnDestroy, OnChanges { - private _overlay = inject(Overlay); private _dir = inject(Directionality, {optional: true}); + private _injector = inject(Injector); private _overlayRef: OverlayRef | undefined; private _templatePortal: TemplatePortal; @@ -293,7 +299,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { this.positions = defaultPositionList; } - const overlayRef = (this._overlayRef = this._overlay.create(this._buildConfig())); + const overlayRef = (this._overlayRef = createOverlayRef(this._injector, this._buildConfig())); this._attachSubscription = overlayRef.attachments().subscribe(() => this.attach.emit()); this._detachSubscription = overlayRef.detachments().subscribe(() => this.detach.emit()); overlayRef.keydownEvents().subscribe((event: KeyboardEvent) => { @@ -379,7 +385,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { /** Returns the position strategy of the overlay to be set on the overlay config */ private _createPositionStrategy(): FlexibleConnectedPositionStrategy { - const strategy = this._overlay.position().flexibleConnectedTo(this._getOrigin()); + const strategy = createFlexibleConnectedPositionStrategy(this._injector, this._getOrigin()); this._updatePositionStrategy(strategy); return strategy; } @@ -463,9 +469,10 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { * @breaking-change 21.0.0 */ export function CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY_PROVIDER_FACTORY( - overlay: Overlay, + overlay: unknown, ): () => RepositionScrollStrategy { - return () => overlay.scrollStrategies.reposition(); + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector); } /** @@ -475,6 +482,5 @@ export function CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY_PROVIDER_FACTORY( */ export const CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY_PROVIDER = { provide: CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY, - deps: [Overlay], useFactory: CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY_PROVIDER_FACTORY, }; diff --git a/src/cdk/overlay/overlay.spec.ts b/src/cdk/overlay/overlay.spec.ts index 53f6b36fa3c7..b723d2fe36f1 100644 --- a/src/cdk/overlay/overlay.spec.ts +++ b/src/cdk/overlay/overlay.spec.ts @@ -5,6 +5,7 @@ import { ErrorHandler, EventEmitter, Injectable, + Injector, Type, ViewChild, ViewContainerRef, @@ -23,6 +24,7 @@ import {Direction, Directionality} from '../bidi'; import {CdkPortal, ComponentPortal, TemplatePortal} from '../portal'; import {dispatchFakeEvent} from '../testing/private'; import { + createOverlayRef, Overlay, OverlayConfig, OverlayContainer, @@ -33,7 +35,7 @@ import { } from './index'; describe('Overlay', () => { - let overlay: Overlay; + let injector: Injector; let componentPortal: ComponentPortal; let templatePortal: TemplatePortal; let overlayContainerElement: HTMLElement; @@ -62,7 +64,7 @@ describe('Overlay', () => { ], }); - overlay = TestBed.inject(Overlay); + injector = TestBed.inject(Injector); overlayContainer = TestBed.inject(OverlayContainer); overlayContainerElement = overlayContainer.getContainerElement(); @@ -82,7 +84,7 @@ describe('Overlay', () => { afterEach(cleanup); it('should load a component into an overlay', () => { - let overlayRef = overlay.create(); + let overlayRef = createOverlayRef(injector); overlayRef.attach(componentPortal); expect(overlayContainerElement.textContent).toContain('Pizza'); @@ -93,7 +95,7 @@ describe('Overlay', () => { }); it('should load a template portal into an overlay', () => { - let overlayRef = overlay.create(); + let overlayRef = createOverlayRef(injector); overlayRef.attach(templatePortal); expect(overlayContainerElement.textContent).toContain('Cake'); @@ -104,7 +106,7 @@ describe('Overlay', () => { }); it('should disable pointer events of the pane element if detached', () => { - let overlayRef = overlay.create(); + let overlayRef = createOverlayRef(injector); let paneElement = overlayRef.overlayElement; overlayRef.attach(componentPortal); @@ -124,10 +126,10 @@ describe('Overlay', () => { }); it('should open multiple overlays', () => { - let pizzaOverlayRef = overlay.create(); + let pizzaOverlayRef = createOverlayRef(injector); pizzaOverlayRef.attach(componentPortal); - let cakeOverlayRef = overlay.create(); + let cakeOverlayRef = createOverlayRef(injector); cakeOverlayRef.attach(templatePortal); expect(overlayContainerElement.childNodes.length).toBe(2); @@ -144,8 +146,8 @@ describe('Overlay', () => { }); it('should ensure that the most-recently-attached overlay is on top', () => { - let pizzaOverlayRef = overlay.create(); - let cakeOverlayRef = overlay.create(); + let pizzaOverlayRef = createOverlayRef(injector); + let cakeOverlayRef = createOverlayRef(injector); pizzaOverlayRef.attach(componentPortal); cakeOverlayRef.attach(templatePortal); @@ -160,7 +162,7 @@ describe('Overlay', () => { pizzaOverlayRef.dispose(); cakeOverlayRef.detach(); - pizzaOverlayRef = overlay.create(); + pizzaOverlayRef = createOverlayRef(injector); pizzaOverlayRef.attach(componentPortal); cakeOverlayRef.attach(templatePortal); @@ -174,7 +176,7 @@ describe('Overlay', () => { it('should take the default direction from the global Directionality', () => { dir = 'rtl'; - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(componentPortal); expect(overlayRef.hostElement.getAttribute('dir')).toBe('rtl'); @@ -182,7 +184,7 @@ describe('Overlay', () => { it('should set the direction', () => { const config = new OverlayConfig({direction: 'rtl'}); - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); @@ -190,7 +192,7 @@ describe('Overlay', () => { }); it('should emit when an overlay is attached', () => { - let overlayRef = overlay.create(); + let overlayRef = createOverlayRef(injector); let spy = jasmine.createSpy('attachments spy'); overlayRef.attachments().subscribe(spy); @@ -201,7 +203,7 @@ describe('Overlay', () => { it('should emit the attachment event after everything is added to the DOM', () => { let config = new OverlayConfig({hasBackdrop: true}); - let overlayRef = overlay.create(config); + let overlayRef = createOverlayRef(injector, config); overlayRef.attachments().subscribe(() => { expect(overlayContainerElement.querySelector('pizza')) @@ -217,7 +219,7 @@ describe('Overlay', () => { }); it('should emit when an overlay is detached', () => { - let overlayRef = overlay.create(); + let overlayRef = createOverlayRef(injector); let spy = jasmine.createSpy('detachments spy'); overlayRef.detachments().subscribe(spy); @@ -228,7 +230,7 @@ describe('Overlay', () => { }); it('should not emit to the detach stream if the overlay has not been attached', () => { - let overlayRef = overlay.create(); + let overlayRef = createOverlayRef(injector); let spy = jasmine.createSpy('detachments spy'); overlayRef.detachments().subscribe(spy); @@ -238,7 +240,7 @@ describe('Overlay', () => { }); it('should not emit to the detach stream on dispose if the overlay was not attached', () => { - let overlayRef = overlay.create(); + let overlayRef = createOverlayRef(injector); let spy = jasmine.createSpy('detachments spy'); overlayRef.detachments().subscribe(spy); @@ -248,7 +250,7 @@ describe('Overlay', () => { }); it('should emit the detachment event after the overlay is removed from the DOM', () => { - let overlayRef = overlay.create(); + let overlayRef = createOverlayRef(injector); overlayRef.detachments().subscribe(() => { expect(overlayContainerElement.querySelector('pizza')) @@ -261,7 +263,7 @@ describe('Overlay', () => { }); it('should emit and complete the observables when an overlay is disposed', () => { - let overlayRef = overlay.create(); + let overlayRef = createOverlayRef(injector); let disposeSpy = jasmine.createSpy('dispose spy'); let attachCompleteSpy = jasmine.createSpy('attachCompleteSpy spy'); let detachCompleteSpy = jasmine.createSpy('detachCompleteSpy spy'); @@ -278,7 +280,7 @@ describe('Overlay', () => { }); it('should complete the attachment observable before the detachment one', () => { - let overlayRef = overlay.create(); + let overlayRef = createOverlayRef(injector); let callbackOrder: string[] = []; overlayRef.attachments().subscribe({complete: () => callbackOrder.push('attach')}); @@ -291,17 +293,17 @@ describe('Overlay', () => { }); it('should default to the ltr direction', () => { - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); expect(overlayRef.getConfig().direction).toBe('ltr'); }); it('should skip undefined values when applying the defaults', () => { - const overlayRef = overlay.create({direction: undefined}); + const overlayRef = createOverlayRef(injector, {direction: undefined}); expect(overlayRef.getConfig().direction).toBe('ltr'); }); it('should clear out all DOM element references on dispose', fakeAsync(() => { - const overlayRef = overlay.create({hasBackdrop: true}); + const overlayRef = createOverlayRef(injector, {hasBackdrop: true}); overlayRef.attach(componentPortal); expect(overlayRef.hostElement).withContext('Expected overlay host to be defined.').toBeTruthy(); @@ -327,7 +329,7 @@ describe('Overlay', () => { })); it('should clear the backdrop timeout if the transition finishes first', fakeAsync(() => { - const overlayRef = overlay.create({hasBackdrop: true}); + const overlayRef = createOverlayRef(injector, {hasBackdrop: true}); overlayRef.attach(componentPortal); overlayRef.detach(); @@ -340,7 +342,7 @@ describe('Overlay', () => { })); it('should clear the backdrop timeout if the overlay is disposed', fakeAsync(() => { - const overlayRef = overlay.create({hasBackdrop: true}); + const overlayRef = createOverlayRef(injector, {hasBackdrop: true}); overlayRef.attach(componentPortal); overlayRef.detach(); overlayRef.dispose(); @@ -373,7 +375,9 @@ describe('Overlay', () => { it('should keep the direction in sync with the passed in Directionality', () => { const customDirectionality = {value: 'rtl', change: new EventEmitter()}; - const overlayRef = overlay.create({direction: customDirectionality as Directionality}); + const overlayRef = createOverlayRef(injector, { + direction: customDirectionality as Directionality, + }); expect(overlayRef.getDirection()).toBe('rtl'); customDirectionality.value = 'ltr'; @@ -381,7 +385,7 @@ describe('Overlay', () => { }); it('should add and remove the overlay host as the ref is being attached and detached', async () => { - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; overlayRef.attach(componentPortal); @@ -416,7 +420,7 @@ describe('Overlay', () => { }); it('should be able to dispose an overlay on navigation', () => { - const overlayRef = overlay.create({disposeOnNavigation: true}); + const overlayRef = createOverlayRef(injector, {disposeOnNavigation: true}); overlayRef.attach(componentPortal); expect(overlayContainerElement.textContent).toContain('Pizza'); @@ -427,7 +431,7 @@ describe('Overlay', () => { }); it('should add and remove classes while open', () => { - let overlayRef = overlay.create(); + let overlayRef = createOverlayRef(injector); overlayRef.attach(componentPortal); const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; @@ -449,7 +453,7 @@ describe('Overlay', () => { }); it('should not throw when trying to add or remove and empty string class', () => { - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(componentPortal); // Empty string @@ -466,7 +470,7 @@ describe('Overlay', () => { }); it('should detach a component-based overlay when the view is destroyed', fakeAsync(() => { - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); const paneElement = overlayRef.overlayElement; overlayRef.attach(componentPortal); @@ -481,7 +485,7 @@ describe('Overlay', () => { })); it('should detach a template-based overlay when the view is destroyed', fakeAsync(() => { - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); const paneElement = overlayRef.overlayElement; overlayRef.attach(templatePortal); @@ -505,7 +509,7 @@ describe('Overlay', () => { it('should apply the positioning strategy', fakeAsync(() => { config.positionStrategy = new FakePositionStrategy(); - overlay.create(config).attach(componentPortal); + createOverlayRef(injector, config).attach(componentPortal); viewContainerFixture.detectChanges(); tick(); @@ -521,7 +525,7 @@ describe('Overlay', () => { dispose: () => {}, }; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); expect(overlayPresentInDom) @@ -542,7 +546,7 @@ describe('Overlay', () => { it('should not apply the position if it detaches before the zone stabilizes', fakeAsync(() => { config.positionStrategy = new FakePositionStrategy(); - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); spyOn(config.positionStrategy, 'apply'); @@ -566,7 +570,7 @@ describe('Overlay', () => { config.positionStrategy = firstStrategy; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); tick(); @@ -598,7 +602,7 @@ describe('Overlay', () => { config.positionStrategy = strategy; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); tick(); @@ -617,7 +621,7 @@ describe('Overlay', () => { })); it('should not throw when disposing multiple times in a row', () => { - const overlayRef = overlay.create(); + const overlayRef = createOverlayRef(injector); overlayRef.attach(componentPortal); expect(overlayContainerElement.textContent).toContain('Pizza'); @@ -630,7 +634,7 @@ describe('Overlay', () => { }); it('should not trigger timers when disposing of an overlay', fakeAsync(() => { - const overlayRef = overlay.create({hasBackdrop: true}); + const overlayRef = createOverlayRef(injector, {hasBackdrop: true}); overlayRef.attach(templatePortal); overlayRef.dispose(); @@ -649,7 +653,7 @@ describe('Overlay', () => { it('should apply the width set in the config', () => { config.width = 500; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); expect(overlayRef.overlayElement.style.width).toBe('500px'); @@ -658,7 +662,7 @@ describe('Overlay', () => { it('should support using other units if a string width is provided', () => { config.width = '200%'; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); expect(overlayRef.overlayElement.style.width).toBe('200%'); @@ -667,7 +671,7 @@ describe('Overlay', () => { it('should apply the height set in the config', () => { config.height = 500; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); expect(overlayRef.overlayElement.style.height).toBe('500px'); @@ -676,7 +680,7 @@ describe('Overlay', () => { it('should support using other units if a string height is provided', () => { config.height = '100vh'; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); expect(overlayRef.overlayElement.style.height).toBe('100vh'); @@ -685,7 +689,7 @@ describe('Overlay', () => { it('should apply the min width set in the config', () => { config.minWidth = 200; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); expect(overlayRef.overlayElement.style.minWidth).toBe('200px'); @@ -694,7 +698,7 @@ describe('Overlay', () => { it('should apply the min height set in the config', () => { config.minHeight = 500; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); expect(overlayRef.overlayElement.style.minHeight).toBe('500px'); @@ -703,7 +707,7 @@ describe('Overlay', () => { it('should apply the max width set in the config', () => { config.maxWidth = 200; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); expect(overlayRef.overlayElement.style.maxWidth).toBe('200px'); @@ -712,7 +716,7 @@ describe('Overlay', () => { it('should apply the max height set in the config', () => { config.maxHeight = 500; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); expect(overlayRef.overlayElement.style.maxHeight).toBe('500px'); @@ -722,7 +726,7 @@ describe('Overlay', () => { config.width = 0; config.height = 0; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); expect(overlayRef.overlayElement.style.width).toBe('0px'); @@ -734,7 +738,7 @@ describe('Overlay', () => { config.width = config.height = 200; config.maxWidth = config.maxHeight = 300; - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); const style = overlayRef.overlayElement.style; @@ -774,7 +778,7 @@ describe('Overlay', () => { }); it('should create and destroy an overlay backdrop', () => { - let overlayRef = overlay.create(config); + let overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); @@ -790,7 +794,7 @@ describe('Overlay', () => { }); it('should complete the backdrop click stream once the overlay is destroyed', () => { - let overlayRef = overlay.create(config); + let overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); @@ -804,7 +808,7 @@ describe('Overlay', () => { }); it('should apply the default overlay backdrop class', () => { - let overlayRef = overlay.create(config); + let overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); @@ -815,7 +819,7 @@ describe('Overlay', () => { it('should apply a custom class to the backdrop', () => { config.backdropClass = 'cdk-overlay-transparent-backdrop'; - let overlayRef = overlay.create(config); + let overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); @@ -826,7 +830,7 @@ describe('Overlay', () => { it('should apply multiple custom classes to the overlay', () => { config.backdropClass = ['custom-class-1', 'custom-class-2']; - let overlayRef = overlay.create(config); + let overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); @@ -836,7 +840,7 @@ describe('Overlay', () => { }); it('should disable the pointer events of a backdrop that is being removed', () => { - let overlayRef = overlay.create(config); + let overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); @@ -850,7 +854,7 @@ describe('Overlay', () => { }); it('should insert the backdrop before the overlay host in the DOM order', () => { - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); @@ -867,7 +871,7 @@ describe('Overlay', () => { }); it('should remove the event listener from the backdrop', () => { - let overlayRef = overlay.create(config); + let overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); @@ -894,7 +898,7 @@ describe('Overlay', () => { TestBed.resetTestingModule(); setup([NoopAnimationsModule]); - let overlayRef = overlay.create(config); + let overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); @@ -908,7 +912,7 @@ describe('Overlay', () => { it('should apply a custom overlay pane class', () => { const config = new OverlayConfig({panelClass: 'custom-panel-class'}); - overlay.create(config).attach(componentPortal); + createOverlayRef(injector, config).attach(componentPortal); viewContainerFixture.detectChanges(); const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; @@ -918,7 +922,7 @@ describe('Overlay', () => { it('should be able to apply multiple classes', () => { const config = new OverlayConfig({panelClass: ['custom-class-one', 'custom-class-two']}); - overlay.create(config).attach(componentPortal); + createOverlayRef(injector, config).attach(componentPortal); viewContainerFixture.detectChanges(); const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; @@ -929,7 +933,7 @@ describe('Overlay', () => { it('should remove the custom panel class when the overlay is detached', async () => { const config = new OverlayConfig({panelClass: 'custom-panel-class'}); - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); @@ -952,7 +956,7 @@ describe('Overlay', () => { it('should wait for the overlay to be detached before removing the panelClass', async () => { const config = new OverlayConfig({panelClass: 'custom-panel-class'}); - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); @@ -980,7 +984,7 @@ describe('Overlay', () => { it('should attach the overlay ref to the scroll strategy', () => { const fakeScrollStrategy = new FakeScrollStrategy(); const config = new OverlayConfig({scrollStrategy: fakeScrollStrategy}); - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); expect(fakeScrollStrategy.overlayRef) .withContext('Expected scroll strategy to have been attached to the current overlay ref.') @@ -990,7 +994,7 @@ describe('Overlay', () => { it('should enable the scroll strategy when the overlay is attached', () => { const fakeScrollStrategy = new FakeScrollStrategy(); const config = new OverlayConfig({scrollStrategy: fakeScrollStrategy}); - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); expect(fakeScrollStrategy.isEnabled) @@ -1001,7 +1005,7 @@ describe('Overlay', () => { it('should disable the scroll strategy once the overlay is detached', () => { const fakeScrollStrategy = new FakeScrollStrategy(); const config = new OverlayConfig({scrollStrategy: fakeScrollStrategy}); - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.attach(componentPortal); expect(fakeScrollStrategy.isEnabled) @@ -1017,7 +1021,7 @@ describe('Overlay', () => { it('should disable the scroll strategy when the overlay is destroyed', () => { const fakeScrollStrategy = new FakeScrollStrategy(); const config = new OverlayConfig({scrollStrategy: fakeScrollStrategy}); - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); overlayRef.dispose(); expect(fakeScrollStrategy.isEnabled) @@ -1028,7 +1032,7 @@ describe('Overlay', () => { it('should detach the scroll strategy when the overlay is destroyed', () => { const fakeScrollStrategy = new FakeScrollStrategy(); const config = new OverlayConfig({scrollStrategy: fakeScrollStrategy}); - const overlayRef = overlay.create(config); + const overlayRef = createOverlayRef(injector, config); expect(fakeScrollStrategy.overlayRef).toBe(overlayRef); @@ -1048,7 +1052,7 @@ describe('Overlay', () => { spyOn(strategy, 'detach'); }); - const overlayRef = overlay.create({scrollStrategy: firstStrategy}); + const overlayRef = createOverlayRef(injector, {scrollStrategy: firstStrategy}); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); @@ -1081,7 +1085,7 @@ describe('Overlay', () => { spyOn(strategy, 'disable'); spyOn(strategy, 'detach'); - const overlayRef = overlay.create({scrollStrategy: strategy}); + const overlayRef = createOverlayRef(injector, {scrollStrategy: strategy}); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); diff --git a/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts b/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts index cc06ed69ee5d..757dd8f92038 100644 --- a/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts +++ b/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts @@ -15,8 +15,9 @@ import {Subscription} from 'rxjs'; import {map} from 'rxjs/operators'; import { ConnectedOverlayPositionChange, + createFlexibleConnectedPositionStrategy, + createOverlayRef, FlexibleConnectedPositionStrategy, - Overlay, OverlayConfig, OverlayContainer, OverlayModule, @@ -28,17 +29,17 @@ const DEFAULT_HEIGHT = 30; const DEFAULT_WIDTH = 60; describe('FlexibleConnectedPositionStrategy', () => { - let overlay: Overlay; let overlayContainer: OverlayContainer; let overlayRef: OverlayRef; let viewport: ViewportRuler; + let injector: Injector; beforeEach(() => { TestBed.configureTestingModule({ imports: [ScrollingModule, OverlayModule, PortalModule, TestOverlay], }); - overlay = TestBed.inject(Overlay); + injector = TestBed.inject(Injector); overlayContainer = TestBed.inject(OverlayContainer); viewport = TestBed.inject(ViewportRuler); }); @@ -52,24 +53,24 @@ describe('FlexibleConnectedPositionStrategy', () => { }); function attachOverlay(config: OverlayConfig) { - overlayRef = overlay.create(config); + overlayRef = createOverlayRef(injector, config); overlayRef.attach(new ComponentPortal(TestOverlay)); TestBed.inject(ApplicationRef).tick(); } it('should throw when attempting to attach to multiple different overlays', () => { const origin = document.createElement('div'); - const positionStrategy = overlay - .position() - .flexibleConnectedTo(origin) - .withPositions([ - { - overlayX: 'start', - overlayY: 'top', - originX: 'start', - originY: 'bottom', - }, - ]); + const positionStrategy = createFlexibleConnectedPositionStrategy( + injector, + origin, + ).withPositions([ + { + overlayX: 'start', + overlayY: 'top', + originX: 'start', + originY: 'bottom', + }, + ]); // Needs to be in the DOM for IE not to throw an "Unspecified error". document.body.appendChild(origin); @@ -82,17 +83,17 @@ describe('FlexibleConnectedPositionStrategy', () => { it('should not throw when trying to apply after being disposed', () => { const origin = document.createElement('div'); - const positionStrategy = overlay - .position() - .flexibleConnectedTo(origin) - .withPositions([ - { - overlayX: 'start', - overlayY: 'top', - originX: 'start', - originY: 'bottom', - }, - ]); + const positionStrategy = createFlexibleConnectedPositionStrategy( + injector, + origin, + ).withPositions([ + { + overlayX: 'start', + overlayY: 'top', + originX: 'start', + originY: 'bottom', + }, + ]); // Needs to be in the DOM for IE not to throw an "Unspecified error". document.body.appendChild(origin); @@ -106,17 +107,17 @@ describe('FlexibleConnectedPositionStrategy', () => { it('should not throw when trying to re-apply the last position after being disposed', () => { const origin = document.createElement('div'); - const positionStrategy = overlay - .position() - .flexibleConnectedTo(origin) - .withPositions([ - { - overlayX: 'start', - overlayY: 'top', - originX: 'start', - originY: 'bottom', - }, - ]); + const positionStrategy = createFlexibleConnectedPositionStrategy( + injector, + origin, + ).withPositions([ + { + overlayX: 'start', + overlayY: 'top', + originX: 'start', + originY: 'bottom', + }, + ]); // Needs to be in the DOM for IE not to throw an "Unspecified error". document.body.appendChild(origin); @@ -141,9 +142,7 @@ describe('FlexibleConnectedPositionStrategy', () => { overlayContainer.getContainerElement().style.top = '-100px'; attachOverlay({ - positionStrategy: overlay - .position() - .flexibleConnectedTo(originElement) + positionStrategy: createFlexibleConnectedPositionStrategy(injector, originElement) .withFlexibleDimensions(false) .withPush(false) .withPositions([ @@ -183,9 +182,7 @@ describe('FlexibleConnectedPositionStrategy', () => { originElement.style.left = '70px'; attachOverlay({ - positionStrategy: overlay - .position() - .flexibleConnectedTo(originElement) + positionStrategy: createFlexibleConnectedPositionStrategy(injector, originElement) .withFlexibleDimensions(false) .withPush(false) .withPositions([ @@ -206,19 +203,19 @@ describe('FlexibleConnectedPositionStrategy', () => { it('should clean up after itself when disposed', () => { const origin = document.createElement('div'); - const positionStrategy = overlay - .position() - .flexibleConnectedTo(origin) - .withPositions([ - { - overlayX: 'start', - overlayY: 'top', - originX: 'start', - originY: 'bottom', - offsetX: 10, - offsetY: 20, - }, - ]); + const positionStrategy = createFlexibleConnectedPositionStrategy( + injector, + origin, + ).withPositions([ + { + overlayX: 'start', + overlayY: 'top', + originX: 'start', + originY: 'bottom', + offsetX: 10, + offsetY: 20, + }, + ]); // Needs to be in the DOM for IE not to throw an "Unspecified error". document.body.appendChild(origin); @@ -263,9 +260,7 @@ describe('FlexibleConnectedPositionStrategy', () => { // The origin and overlay elements need to be in the document body in order to have geometry. originElement = createPositionedBlockElement(); document.body.appendChild(originElement); - positionStrategy = overlay - .position() - .flexibleConnectedTo(originElement) + positionStrategy = createFlexibleConnectedPositionStrategy(injector, originElement) .withFlexibleDimensions(false) .withPush(false); }); @@ -1248,9 +1243,7 @@ describe('FlexibleConnectedPositionStrategy', () => { beforeEach(() => { originElement = createPositionedBlockElement(); document.body.appendChild(originElement); - positionStrategy = overlay - .position() - .flexibleConnectedTo(originElement) + positionStrategy = createFlexibleConnectedPositionStrategy(injector, originElement) .withFlexibleDimensions(false) .withPush(); }); @@ -1573,7 +1566,7 @@ describe('FlexibleConnectedPositionStrategy', () => { beforeEach(() => { originElement = createPositionedBlockElement(); document.body.appendChild(originElement); - positionStrategy = overlay.position().flexibleConnectedTo(originElement); + positionStrategy = createFlexibleConnectedPositionStrategy(injector, originElement); }); afterEach(() => { @@ -2482,20 +2475,6 @@ describe('FlexibleConnectedPositionStrategy', () => { document.body.appendChild(scrollable); scrollable.appendChild(originElement); - // Create a strategy with knowledge of the scrollable container - const strategy = overlay - .position() - .flexibleConnectedTo(originElement) - .withPush(false) - .withPositions([ - { - originX: 'start', - originY: 'bottom', - overlayX: 'start', - overlayY: 'top', - }, - ]); - const injector = Injector.create({ parent: TestBed.inject(Injector), providers: [ @@ -2510,6 +2489,18 @@ describe('FlexibleConnectedPositionStrategy', () => { ], }); + // Create a strategy with knowledge of the scrollable container + const strategy = createFlexibleConnectedPositionStrategy(injector, originElement) + .withPush(false) + .withPositions([ + { + originX: 'start', + originY: 'bottom', + overlayX: 'start', + overlayY: 'top', + }, + ]); + runInInjectionContext(injector, () => { strategy.withScrollableContainers([new CdkScrollable()]); }); @@ -2588,7 +2579,7 @@ describe('FlexibleConnectedPositionStrategy', () => { beforeEach(() => { originElement = createPositionedBlockElement(); document.body.appendChild(originElement); - positionStrategy = overlay.position().flexibleConnectedTo(originElement); + positionStrategy = createFlexibleConnectedPositionStrategy(injector, originElement); }); afterEach(() => { @@ -2708,7 +2699,7 @@ describe('FlexibleConnectedPositionStrategy', () => { beforeEach(() => { originElement = createPositionedBlockElement(); document.body.appendChild(originElement); - positionStrategy = overlay.position().flexibleConnectedTo(originElement); + positionStrategy = createFlexibleConnectedPositionStrategy(injector, originElement); }); afterEach(() => { @@ -2766,9 +2757,7 @@ describe('FlexibleConnectedPositionStrategy', () => { beforeEach(() => { originElement = createPositionedBlockElement(); document.body.appendChild(originElement); - positionStrategy = overlay - .position() - .flexibleConnectedTo(originElement) + positionStrategy = createFlexibleConnectedPositionStrategy(injector, originElement) .withFlexibleDimensions(false) .withPush(false); }); diff --git a/src/cdk/overlay/position/global-position-strategy.spec.ts b/src/cdk/overlay/position/global-position-strategy.spec.ts index 5588702b1b30..e0c7f8080420 100644 --- a/src/cdk/overlay/position/global-position-strategy.spec.ts +++ b/src/cdk/overlay/position/global-position-strategy.spec.ts @@ -1,18 +1,24 @@ -import {Component, ApplicationRef} from '@angular/core'; +import {Component, ApplicationRef, Injector} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {PortalModule, ComponentPortal} from '../../portal'; -import {OverlayModule, Overlay, OverlayConfig, OverlayRef} from '../index'; +import { + OverlayModule, + OverlayConfig, + OverlayRef, + createOverlayRef, + createGlobalPositionStrategy, +} from '../index'; describe('GlobalPositonStrategy', () => { let overlayRef: OverlayRef; - let overlay: Overlay; + let injector: Injector; beforeEach(() => { TestBed.configureTestingModule({ imports: [OverlayModule, PortalModule, BlankPortal], }); - overlay = TestBed.inject(Overlay); + injector = TestBed.inject(Injector); }); afterEach(() => { @@ -24,7 +30,7 @@ describe('GlobalPositonStrategy', () => { function attachOverlay(config: OverlayConfig): OverlayRef { const portal = new ComponentPortal(BlankPortal); - overlayRef = overlay.create(config); + overlayRef = createOverlayRef(injector, config); overlayRef.attach(portal); TestBed.inject(ApplicationRef).tick(); return overlayRef; @@ -32,7 +38,7 @@ describe('GlobalPositonStrategy', () => { it('should position the element to the (top, left) with an offset', () => { attachOverlay({ - positionStrategy: overlay.position().global().top('10px').left('40px'), + positionStrategy: createGlobalPositionStrategy(injector).top('10px').left('40px'), }); const elementStyle = overlayRef.overlayElement.style; @@ -49,7 +55,7 @@ describe('GlobalPositonStrategy', () => { it('should position the element to the (bottom, right) with an offset', () => { attachOverlay({ - positionStrategy: overlay.position().global().bottom('70px').right('15em'), + positionStrategy: createGlobalPositionStrategy(injector).bottom('70px').right('15em'), }); const elementStyle = overlayRef.overlayElement.style; @@ -65,7 +71,9 @@ describe('GlobalPositonStrategy', () => { }); it('should overwrite previously applied positioning', () => { - const positionStrategy = overlay.position().global().centerHorizontally().centerVertically(); + const positionStrategy = createGlobalPositionStrategy(injector) + .centerHorizontally() + .centerVertically(); attachOverlay({positionStrategy}); positionStrategy.top('10px').left('40%'); @@ -96,7 +104,7 @@ describe('GlobalPositonStrategy', () => { it('should not set any alignment by default', () => { attachOverlay({ - positionStrategy: overlay.position().global(), + positionStrategy: createGlobalPositionStrategy(injector), }); const parentStyle = (overlayRef.overlayElement.parentNode as HTMLElement).style; @@ -107,7 +115,9 @@ describe('GlobalPositonStrategy', () => { it('should center the element', () => { attachOverlay({ - positionStrategy: overlay.position().global().centerHorizontally().centerVertically(), + positionStrategy: createGlobalPositionStrategy(injector) + .centerHorizontally() + .centerVertically(), }); const parentStyle = (overlayRef.overlayElement.parentNode as HTMLElement).style; @@ -118,9 +128,7 @@ describe('GlobalPositonStrategy', () => { it('should center the element with an offset', () => { attachOverlay({ - positionStrategy: overlay - .position() - .global() + positionStrategy: createGlobalPositionStrategy(injector) .centerHorizontally('10px') .centerVertically('15px'), }); @@ -140,9 +148,7 @@ describe('GlobalPositonStrategy', () => { it('should center the element with an offset in rtl', () => { attachOverlay({ direction: 'rtl', - positionStrategy: overlay - .position() - .global() + positionStrategy: createGlobalPositionStrategy(injector) .centerHorizontally('10px') .centerVertically('15px'), }); @@ -160,7 +166,7 @@ describe('GlobalPositonStrategy', () => { it('should make the element position: static', () => { attachOverlay({ - positionStrategy: overlay.position().global(), + positionStrategy: createGlobalPositionStrategy(injector), }); expect(overlayRef.overlayElement.style.position).toBe('static'); @@ -168,7 +174,7 @@ describe('GlobalPositonStrategy', () => { it('should wrap the element in a `cdk-global-overlay-wrapper`', () => { attachOverlay({ - positionStrategy: overlay.position().global(), + positionStrategy: createGlobalPositionStrategy(injector), }); const parent = overlayRef.overlayElement.parentNode as HTMLElement; @@ -178,7 +184,7 @@ describe('GlobalPositonStrategy', () => { it('should remove the parent wrapper from the DOM', () => { attachOverlay({ - positionStrategy: overlay.position().global(), + positionStrategy: createGlobalPositionStrategy(injector), }); const parent = overlayRef.overlayElement.parentNode!; @@ -192,7 +198,7 @@ describe('GlobalPositonStrategy', () => { it('should set the element width', () => { attachOverlay({ - positionStrategy: overlay.position().global().width('100px'), + positionStrategy: createGlobalPositionStrategy(injector).width('100px'), }); expect(overlayRef.overlayElement.style.width).toBe('100px'); @@ -200,7 +206,7 @@ describe('GlobalPositonStrategy', () => { it('should set the element height', () => { attachOverlay({ - positionStrategy: overlay.position().global().height('100px'), + positionStrategy: createGlobalPositionStrategy(injector).height('100px'), }); expect(overlayRef.overlayElement.style.height).toBe('100px'); @@ -208,7 +214,9 @@ describe('GlobalPositonStrategy', () => { it('should reset the horizontal position and offset when the width is 100%', () => { attachOverlay({ - positionStrategy: overlay.position().global().centerHorizontally('10px').width('100%'), + positionStrategy: createGlobalPositionStrategy(injector) + .centerHorizontally('10px') + .width('100%'), }); const elementStyle = overlayRef.overlayElement.style; @@ -224,7 +232,9 @@ describe('GlobalPositonStrategy', () => { () => { attachOverlay({ maxWidth: '100%', - positionStrategy: overlay.position().global().centerHorizontally('10px').width('100%'), + positionStrategy: createGlobalPositionStrategy(injector) + .centerHorizontally('10px') + .width('100%'), }); const elementStyle = overlayRef.overlayElement.style; @@ -241,7 +251,9 @@ describe('GlobalPositonStrategy', () => { () => { attachOverlay({ maxWidth: '500px', - positionStrategy: overlay.position().global().centerHorizontally('10px').width('100%'), + positionStrategy: createGlobalPositionStrategy(injector) + .centerHorizontally('10px') + .width('100%'), }); const elementStyle = overlayRef.overlayElement.style; @@ -254,7 +266,9 @@ describe('GlobalPositonStrategy', () => { it('should reset the vertical position and offset when the height is 100%', () => { attachOverlay({ - positionStrategy: overlay.position().global().centerVertically('10px').height('100%'), + positionStrategy: createGlobalPositionStrategy(injector) + .centerVertically('10px') + .height('100%'), }); const elementStyle = overlayRef.overlayElement.style; @@ -270,7 +284,9 @@ describe('GlobalPositonStrategy', () => { () => { attachOverlay({ maxHeight: '100%', - positionStrategy: overlay.position().global().centerVertically('10px').height('100%'), + positionStrategy: createGlobalPositionStrategy(injector) + .centerVertically('10px') + .height('100%'), }); const elementStyle = overlayRef.overlayElement.style; @@ -287,7 +303,9 @@ describe('GlobalPositonStrategy', () => { () => { attachOverlay({ maxHeight: '500px', - positionStrategy: overlay.position().global().centerVertically('10px').height('100%'), + positionStrategy: createGlobalPositionStrategy(injector) + .centerVertically('10px') + .height('100%'), }); const elementStyle = overlayRef.overlayElement.style; @@ -299,7 +317,7 @@ describe('GlobalPositonStrategy', () => { ); it('should not throw when attempting to apply after the overlay has been disposed', () => { - const positionStrategy = overlay.position().global(); + const positionStrategy = createGlobalPositionStrategy(injector); attachOverlay({positionStrategy}); @@ -310,7 +328,7 @@ describe('GlobalPositonStrategy', () => { it('should take its width and height from the overlay config', () => { attachOverlay({ - positionStrategy: overlay.position().global(), + positionStrategy: createGlobalPositionStrategy(injector), width: '500px', height: '300px', }); @@ -323,7 +341,7 @@ describe('GlobalPositonStrategy', () => { it('should update the overlay size when setting it through the position strategy', () => { attachOverlay({ - positionStrategy: overlay.position().global().width('500px').height('300px'), + positionStrategy: createGlobalPositionStrategy(injector).width('500px').height('300px'), }); expect(overlayRef.getConfig().width).toBe('500px'); @@ -335,7 +353,7 @@ describe('GlobalPositonStrategy', () => { 'config and the strategy', () => { attachOverlay({ - positionStrategy: overlay.position().global().width('200px').height('100px'), + positionStrategy: createGlobalPositionStrategy(injector).width('200px').height('100px'), width: '500px', height: '300px', }); @@ -350,7 +368,9 @@ describe('GlobalPositonStrategy', () => { it('should center the element in RTL', () => { attachOverlay({ direction: 'rtl', - positionStrategy: overlay.position().global().centerHorizontally().centerVertically(), + positionStrategy: createGlobalPositionStrategy(injector) + .centerHorizontally() + .centerVertically(), }); const parentStyle = (overlayRef.overlayElement.parentNode as HTMLElement).style; @@ -360,7 +380,7 @@ describe('GlobalPositonStrategy', () => { it('should invert `justify-content` when using `left` in RTL', () => { attachOverlay({ - positionStrategy: overlay.position().global().left('0'), + positionStrategy: createGlobalPositionStrategy(injector).left('0'), direction: 'rtl', }); @@ -370,7 +390,7 @@ describe('GlobalPositonStrategy', () => { it('should invert `justify-content` when using `right` in RTL', () => { attachOverlay({ - positionStrategy: overlay.position().global().right('0'), + positionStrategy: createGlobalPositionStrategy(injector).right('0'), direction: 'rtl', }); @@ -379,7 +399,7 @@ describe('GlobalPositonStrategy', () => { }); it('should clean up after itself when it has been disposed', () => { - const positionStrategy = overlay.position().global().top('10px').left('40px'); + const positionStrategy = createGlobalPositionStrategy(injector).top('10px').left('40px'); attachOverlay({positionStrategy}); @@ -401,7 +421,7 @@ describe('GlobalPositonStrategy', () => { it('should position the overlay to the start in ltr', () => { attachOverlay({ direction: 'ltr', - positionStrategy: overlay.position().global().start('40px'), + positionStrategy: createGlobalPositionStrategy(injector).start('40px'), }); const elementStyle = overlayRef.overlayElement.style; @@ -415,7 +435,7 @@ describe('GlobalPositonStrategy', () => { it('should position the overlay to the start in rtl', () => { attachOverlay({ direction: 'rtl', - positionStrategy: overlay.position().global().start('50px'), + positionStrategy: createGlobalPositionStrategy(injector).start('50px'), }); const elementStyle = overlayRef.overlayElement.style; @@ -429,7 +449,7 @@ describe('GlobalPositonStrategy', () => { it('should position the overlay to the end in ltr', () => { attachOverlay({ direction: 'ltr', - positionStrategy: overlay.position().global().end('60px'), + positionStrategy: createGlobalPositionStrategy(injector).end('60px'), }); const elementStyle = overlayRef.overlayElement.style; @@ -443,7 +463,7 @@ describe('GlobalPositonStrategy', () => { it('should position the overlay to the end in rtl', () => { attachOverlay({ direction: 'rtl', - positionStrategy: overlay.position().global().end('70px'), + positionStrategy: createGlobalPositionStrategy(injector).end('70px'), }); const elementStyle = overlayRef.overlayElement.style; diff --git a/src/cdk/overlay/scroll/block-scroll-strategy.spec.ts b/src/cdk/overlay/scroll/block-scroll-strategy.spec.ts index f7353e3f720a..c7aaa6a2b826 100644 --- a/src/cdk/overlay/scroll/block-scroll-strategy.spec.ts +++ b/src/cdk/overlay/scroll/block-scroll-strategy.spec.ts @@ -1,9 +1,16 @@ -import {Component} from '@angular/core'; +import {Component, Injector} from '@angular/core'; import {waitForAsync, TestBed} from '@angular/core/testing'; import {ComponentPortal, PortalModule} from '../../portal'; import {Platform} from '../../platform'; import {ViewportRuler} from '../../scrolling'; -import {Overlay, OverlayContainer, OverlayModule, OverlayRef, OverlayConfig} from '../index'; +import { + OverlayContainer, + OverlayModule, + OverlayRef, + OverlayConfig, + createBlockScrollStrategy, + createOverlayRef, +} from '../index'; describe('BlockScrollStrategy', () => { let platform: Platform; @@ -17,13 +24,13 @@ describe('BlockScrollStrategy', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({imports: [OverlayModule, PortalModule, FocacciaMsg]}); - const overlay = TestBed.inject(Overlay); - const overlayConfig = new OverlayConfig({scrollStrategy: overlay.scrollStrategies.block()}); + const injector = TestBed.inject(Injector); + const overlayConfig = new OverlayConfig({scrollStrategy: createBlockScrollStrategy(injector)}); viewport = TestBed.inject(ViewportRuler); platform = TestBed.inject(Platform); overlayContainer = TestBed.inject(OverlayContainer); - overlayRef = overlay.create(overlayConfig); + overlayRef = createOverlayRef(injector, overlayConfig); componentPortal = new ComponentPortal(FocacciaMsg); documentElement = document.documentElement!; documentElement.classList.remove('cdk-global-scrollblock'); diff --git a/src/cdk/overlay/scroll/close-scroll-strategy.spec.ts b/src/cdk/overlay/scroll/close-scroll-strategy.spec.ts index 2eac586b25ea..60c338a39fa6 100644 --- a/src/cdk/overlay/scroll/close-scroll-strategy.spec.ts +++ b/src/cdk/overlay/scroll/close-scroll-strategy.spec.ts @@ -1,9 +1,16 @@ import {ComponentPortal, PortalModule} from '../../portal'; import {CdkScrollable, ScrollDispatcher, ViewportRuler} from '../../scrolling'; -import {Component, ElementRef} from '@angular/core'; +import {Component, ElementRef, Injector} from '@angular/core'; import {TestBed, fakeAsync} from '@angular/core/testing'; import {Subject} from 'rxjs'; -import {Overlay, OverlayConfig, OverlayContainer, OverlayModule, OverlayRef} from '../index'; +import { + createCloseScrollStrategy, + createOverlayRef, + OverlayConfig, + OverlayContainer, + OverlayModule, + OverlayRef, +} from '../index'; describe('CloseScrollStrategy', () => { let overlayRef: OverlayRef; @@ -11,7 +18,7 @@ describe('CloseScrollStrategy', () => { let scrolledSubject = new Subject(); let scrollPosition: number; let overlayContainer: OverlayContainer; - let overlay: Overlay; + let injector: Injector; beforeEach(fakeAsync(() => { scrollPosition = 0; @@ -35,9 +42,9 @@ describe('CloseScrollStrategy', () => { }); overlayContainer = TestBed.inject(OverlayContainer); - overlay = TestBed.inject(Overlay); - const overlayConfig = new OverlayConfig({scrollStrategy: overlay.scrollStrategies.close()}); - overlayRef = overlay.create(overlayConfig); + injector = TestBed.inject(Injector); + const overlayConfig = new OverlayConfig({scrollStrategy: createCloseScrollStrategy(injector)}); + overlayRef = createOverlayRef(injector, overlayConfig); componentPortal = new ComponentPortal(MozarellaMsg); })); @@ -77,8 +84,8 @@ describe('CloseScrollStrategy', () => { it('should be able to reposition the overlay up to a certain threshold before closing', () => { overlayRef.dispose(); - overlayRef = overlay.create({ - scrollStrategy: overlay.scrollStrategies.close({threshold: 50}), + overlayRef = createOverlayRef(injector, { + scrollStrategy: createCloseScrollStrategy(injector, {threshold: 50}), }); overlayRef.attach(componentPortal); @@ -103,8 +110,8 @@ describe('CloseScrollStrategy', () => { overlayRef.dispose(); scrollPosition = 100; - overlayRef = overlay.create({ - scrollStrategy: overlay.scrollStrategies.close({threshold: 50}), + overlayRef = createOverlayRef(injector, { + scrollStrategy: createCloseScrollStrategy(injector, {threshold: 50}), }); overlayRef.attach(componentPortal); diff --git a/src/cdk/overlay/scroll/close-scroll-strategy.zone.spec.ts b/src/cdk/overlay/scroll/close-scroll-strategy.zone.spec.ts index 99a2572bcbdb..d695f1a309ff 100644 --- a/src/cdk/overlay/scroll/close-scroll-strategy.zone.spec.ts +++ b/src/cdk/overlay/scroll/close-scroll-strategy.zone.spec.ts @@ -1,13 +1,18 @@ import {ComponentPortal, PortalModule} from '../../portal'; -import {Component, NgZone, provideZoneChangeDetection} from '@angular/core'; +import {Component, Injector, NgZone, provideZoneChangeDetection} from '@angular/core'; import {TestBed, fakeAsync} from '@angular/core/testing'; import {Subject} from 'rxjs'; -import {Overlay} from '../overlay'; import {OverlayConfig} from '../overlay-config'; import {OverlayContainer} from '../overlay-container'; import {OverlayModule} from '../overlay-module'; import {OverlayRef} from '../overlay-ref'; -import {CdkScrollable, ScrollDispatcher, ViewportRuler} from '../public-api'; +import { + CdkScrollable, + createCloseScrollStrategy, + createOverlayRef, + ScrollDispatcher, + ViewportRuler, +} from '../public-api'; describe('CloseScrollStrategy Zone.js integration', () => { let overlayRef: OverlayRef; @@ -38,9 +43,9 @@ describe('CloseScrollStrategy Zone.js integration', () => { ], }); - const overlay = TestBed.inject(Overlay); - const overlayConfig = new OverlayConfig({scrollStrategy: overlay.scrollStrategies.close()}); - overlayRef = overlay.create(overlayConfig); + const injector = TestBed.inject(Injector); + const overlayConfig = new OverlayConfig({scrollStrategy: createCloseScrollStrategy(injector)}); + overlayRef = createOverlayRef(injector, overlayConfig); componentPortal = new ComponentPortal(MozarellaMsg); overlayContainer = TestBed.inject(OverlayContainer); })); diff --git a/src/cdk/overlay/scroll/reposition-scroll-strategy.spec.ts b/src/cdk/overlay/scroll/reposition-scroll-strategy.spec.ts index 412051b9feff..8a1c9effce12 100644 --- a/src/cdk/overlay/scroll/reposition-scroll-strategy.spec.ts +++ b/src/cdk/overlay/scroll/reposition-scroll-strategy.spec.ts @@ -1,19 +1,20 @@ import {waitForAsync, TestBed} from '@angular/core/testing'; -import {Component} from '@angular/core'; +import {Component, Injector} from '@angular/core'; import {Subject} from 'rxjs'; import {ComponentPortal, PortalModule} from '../../portal'; import { - Overlay, OverlayContainer, OverlayModule, OverlayRef, OverlayConfig, ScrollDispatcher, + createRepositionScrollStrategy, + createOverlayRef, } from '../index'; describe('RepositionScrollStrategy', () => { + let injector: Injector; let overlayRef: OverlayRef; - let overlay: Overlay; let overlayContainer: OverlayContainer; let componentPortal: ComponentPortal; let scrolledSubject = new Subject(); @@ -31,7 +32,7 @@ describe('RepositionScrollStrategy', () => { ], }); - overlay = TestBed.inject(Overlay); + injector = TestBed.inject(Injector); overlayContainer = TestBed.inject(OverlayContainer); componentPortal = new ComponentPortal(PastaMsg); })); @@ -43,10 +44,10 @@ describe('RepositionScrollStrategy', () => { it('should update the overlay position when the page is scrolled', () => { const overlayConfig = new OverlayConfig({ - scrollStrategy: overlay.scrollStrategies.reposition(), + scrollStrategy: createRepositionScrollStrategy(injector), }); - overlayRef = overlay.create(overlayConfig); + overlayRef = createOverlayRef(injector, overlayConfig); overlayRef.attach(componentPortal); spyOn(overlayRef, 'updatePosition'); @@ -59,10 +60,10 @@ describe('RepositionScrollStrategy', () => { it('should not be updating the position after the overlay is detached', () => { const overlayConfig = new OverlayConfig({ - scrollStrategy: overlay.scrollStrategies.reposition(), + scrollStrategy: createRepositionScrollStrategy(injector), }); - overlayRef = overlay.create(overlayConfig); + overlayRef = createOverlayRef(injector, overlayConfig); overlayRef.attach(componentPortal); spyOn(overlayRef, 'updatePosition'); @@ -74,10 +75,10 @@ describe('RepositionScrollStrategy', () => { it('should not be updating the position after the overlay is destroyed', () => { const overlayConfig = new OverlayConfig({ - scrollStrategy: overlay.scrollStrategies.reposition(), + scrollStrategy: createRepositionScrollStrategy(injector), }); - overlayRef = overlay.create(overlayConfig); + overlayRef = createOverlayRef(injector, overlayConfig); overlayRef.attach(componentPortal); spyOn(overlayRef, 'updatePosition'); @@ -89,12 +90,12 @@ describe('RepositionScrollStrategy', () => { it('should be able to close the overlay once it is out of view', () => { const overlayConfig = new OverlayConfig({ - scrollStrategy: overlay.scrollStrategies.reposition({ + scrollStrategy: createRepositionScrollStrategy(injector, { autoClose: true, }), }); - overlayRef = overlay.create(overlayConfig); + overlayRef = createOverlayRef(injector, overlayConfig); overlayRef.attach(componentPortal); spyOn(overlayRef, 'updatePosition'); spyOn(overlayRef, 'detach'); diff --git a/src/components-examples/cdk/drag-drop/cdk-drag-drop-root-element/cdk-drag-drop-root-element-example.ts b/src/components-examples/cdk/drag-drop/cdk-drag-drop-root-element/cdk-drag-drop-root-element-example.ts index 9758542d8068..44857bd39fe6 100644 --- a/src/components-examples/cdk/drag-drop/cdk-drag-drop-root-element/cdk-drag-drop-root-element-example.ts +++ b/src/components-examples/cdk/drag-drop/cdk-drag-drop-root-element/cdk-drag-drop-root-element-example.ts @@ -6,8 +6,9 @@ import { ViewContainerRef, OnDestroy, inject, + Injector, } from '@angular/core'; -import {Overlay, OverlayRef} from '@angular/cdk/overlay'; +import {createGlobalPositionStrategy, createOverlayRef, OverlayRef} from '@angular/cdk/overlay'; import {TemplatePortal} from '@angular/cdk/portal'; import {CdkDrag} from '@angular/cdk/drag-drop'; @@ -21,7 +22,7 @@ import {CdkDrag} from '@angular/cdk/drag-drop'; imports: [CdkDrag], }) export class CdkDragDropRootElementExample implements AfterViewInit, OnDestroy { - private _overlay = inject(Overlay); + private _injector = inject(Injector); private _viewContainerRef = inject(ViewContainerRef); @ViewChild(TemplateRef) _dialogTemplate: TemplateRef; @@ -30,8 +31,10 @@ export class CdkDragDropRootElementExample implements AfterViewInit, OnDestroy { ngAfterViewInit() { this._portal = new TemplatePortal(this._dialogTemplate, this._viewContainerRef); - this._overlayRef = this._overlay.create({ - positionStrategy: this._overlay.position().global().centerHorizontally().centerVertically(), + this._overlayRef = createOverlayRef(this._injector, { + positionStrategy: createGlobalPositionStrategy(this._injector) + .centerHorizontally() + .centerVertically(), hasBackdrop: true, }); this._overlayRef.backdropClick().subscribe(() => this._overlayRef.detach()); diff --git a/src/dev-app/connected-overlay/connected-overlay-demo.ts b/src/dev-app/connected-overlay/connected-overlay-demo.ts index b7ff9f5af011..c9107f325620 100644 --- a/src/dev-app/connected-overlay/connected-overlay-demo.ts +++ b/src/dev-app/connected-overlay/connected-overlay-demo.ts @@ -9,8 +9,10 @@ import {Directionality} from '@angular/cdk/bidi'; import { CdkOverlayOrigin, + createFlexibleConnectedPositionStrategy, + createOverlayRef, + createRepositionScrollStrategy, HorizontalConnectionPos, - Overlay, OverlayModule, OverlayRef, VerticalConnectionPos, @@ -20,6 +22,7 @@ import {CdkOverlayBasicExample} from '@angular/components-examples/cdk/overlay'; import { ChangeDetectionStrategy, Component, + Injector, TemplateRef, ViewChild, ViewContainerRef, @@ -47,7 +50,7 @@ import {MatRadioModule} from '@angular/material/radio'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class ConnectedOverlayDemo { - overlay = inject(Overlay); + private _injector = inject(Injector); viewContainerRef = inject(ViewContainerRef); dir = inject(Directionality); @@ -69,9 +72,10 @@ export class ConnectedOverlayDemo { overlayRef: OverlayRef | null; openWithConfig() { - const positionStrategy = this.overlay - .position() - .flexibleConnectedTo(this._overlayOrigin.elementRef) + const positionStrategy = createFlexibleConnectedPositionStrategy( + this._injector, + this._overlayOrigin.elementRef, + ) .withFlexibleDimensions(this.isFlexible) .withPush(this.canPush) .withViewportMargin(10) @@ -99,9 +103,9 @@ export class ConnectedOverlayDemo { }, ]); - this.overlayRef = this.overlay.create({ + this.overlayRef = createOverlayRef(this._injector, { positionStrategy, - scrollStrategy: this.overlay.scrollStrategies.reposition(), + scrollStrategy: createRepositionScrollStrategy(this._injector), direction: this.dir.value, minWidth: 200, minHeight: 50, diff --git a/src/e2e-app/components/block-scroll-strategy/block-scroll-strategy-e2e.ts b/src/e2e-app/components/block-scroll-strategy/block-scroll-strategy-e2e.ts index 8e515a71e941..8f96070568e3 100644 --- a/src/e2e-app/components/block-scroll-strategy/block-scroll-strategy-e2e.ts +++ b/src/e2e-app/components/block-scroll-strategy/block-scroll-strategy-e2e.ts @@ -1,5 +1,5 @@ -import {Component, inject} from '@angular/core'; -import {Overlay, OverlayContainer} from '@angular/cdk/overlay'; +import {Component, inject, Injector} from '@angular/core'; +import {createBlockScrollStrategy, OverlayContainer} from '@angular/cdk/overlay'; import {ScrollingModule} from '@angular/cdk/scrolling'; @Component({ @@ -9,7 +9,7 @@ import {ScrollingModule} from '@angular/cdk/scrolling'; imports: [ScrollingModule], }) export class BlockScrollStrategyE2E { - scrollStrategy = inject(Overlay).scrollStrategies.block(); + scrollStrategy = createBlockScrollStrategy(inject(Injector)); constructor() { // This loads the structural styles for the test. diff --git a/src/material-experimental/column-resize/resizable-directives/default-enabled-resizable.ts b/src/material-experimental/column-resize/resizable-directives/default-enabled-resizable.ts index 56eb32bb10f2..3a6eca406350 100644 --- a/src/material-experimental/column-resize/resizable-directives/default-enabled-resizable.ts +++ b/src/material-experimental/column-resize/resizable-directives/default-enabled-resizable.ts @@ -18,7 +18,6 @@ import { } from '@angular/core'; import {Directionality} from '@angular/cdk/bidi'; -import {Overlay} from '@angular/cdk/overlay'; import { CdkColumnDef, _CoalescedStyleScheduler, @@ -50,7 +49,6 @@ export class MatDefaultResizable extends AbstractMatResizable { protected readonly eventDispatcher = inject(HeaderRowEventDispatcher); protected readonly injector = inject(Injector); protected readonly ngZone = inject(NgZone); - protected readonly overlay = inject(Overlay); protected readonly resizeNotifier = inject(ColumnResizeNotifierSource); protected readonly resizeStrategy = inject(ResizeStrategy); protected readonly styleScheduler = inject<_CoalescedStyleScheduler>(_COALESCED_STYLE_SCHEDULER); diff --git a/src/material-experimental/column-resize/resizable-directives/resizable.ts b/src/material-experimental/column-resize/resizable-directives/resizable.ts index 5047197a1bf2..11a0faa19851 100644 --- a/src/material-experimental/column-resize/resizable-directives/resizable.ts +++ b/src/material-experimental/column-resize/resizable-directives/resizable.ts @@ -18,7 +18,6 @@ import { } from '@angular/core'; import {Directionality} from '@angular/cdk/bidi'; -import {Overlay} from '@angular/cdk/overlay'; import { CdkColumnDef, _CoalescedStyleScheduler, @@ -49,7 +48,6 @@ export class MatResizable extends AbstractMatResizable { protected readonly eventDispatcher = inject(HeaderRowEventDispatcher); protected readonly injector = inject(Injector); protected readonly ngZone = inject(NgZone); - protected readonly overlay = inject(Overlay); protected readonly resizeNotifier = inject(ColumnResizeNotifierSource); protected readonly resizeStrategy = inject(ResizeStrategy); protected readonly styleScheduler = inject<_CoalescedStyleScheduler>(_COALESCED_STYLE_SCHEDULER); diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts index 7095fa5773a1..7ddf9fc79ef4 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -12,8 +12,10 @@ import {DOWN_ARROW, ENTER, ESCAPE, TAB, UP_ARROW, hasModifierKey} from '@angular import {BreakpointObserver, Breakpoints} from '@angular/cdk/layout'; import { ConnectedPosition, + createFlexibleConnectedPositionStrategy, + createOverlayRef, + createRepositionScrollStrategy, FlexibleConnectedPositionStrategy, - Overlay, OverlayConfig, OverlayRef, PositionStrategy, @@ -29,6 +31,7 @@ import { ElementRef, EnvironmentInjector, InjectionToken, + Injector, Input, NgZone, OnChanges, @@ -88,8 +91,8 @@ export const MAT_AUTOCOMPLETE_SCROLL_STRATEGY = new InjectionToken<() => ScrollS { providedIn: 'root', factory: () => { - const overlay = inject(Overlay); - return () => overlay.scrollStrategies.reposition(); + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector); }, }, ); @@ -99,8 +102,9 @@ export const MAT_AUTOCOMPLETE_SCROLL_STRATEGY = new InjectionToken<() => ScrollS * @deprecated No longer used, will be removed. * @breaking-change 21.0.0 */ -export function MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy { - return () => overlay.scrollStrategies.reposition(); +export function MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY(_overlay: unknown): () => ScrollStrategy { + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector); } /** @@ -110,7 +114,7 @@ export function MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () = */ export const MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY_PROVIDER = { provide: MAT_AUTOCOMPLETE_SCROLL_STRATEGY, - deps: [Overlay], + deps: [] as any[], useFactory: MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY, }; @@ -142,7 +146,7 @@ export class MatAutocompleteTrigger { private _environmentInjector = inject(EnvironmentInjector); private _element = inject>(ElementRef); - private _overlay = inject(Overlay); + private _injector = inject(Injector); private _viewContainerRef = inject(ViewContainerRef); private _zone = inject(NgZone); private _changeDetectorRef = inject(ChangeDetectorRef); @@ -794,7 +798,7 @@ export class MatAutocompleteTrigger this._portal = new TemplatePortal(this.autocomplete.template, this._viewContainerRef, { id: this._formField?.getLabelId(), }); - overlayRef = this._overlay.create(this._getOverlayConfig()); + overlayRef = createOverlayRef(this._injector, this._getOverlayConfig()); this._overlayRef = overlayRef; this._viewportSubscription = this._viewportRuler.change().subscribe(() => { if (this.panelOpen && overlayRef) { @@ -916,9 +920,10 @@ export class MatAutocompleteTrigger private _getOverlayPosition(): PositionStrategy { // Set default Overlay Position - const strategy = this._overlay - .position() - .flexibleConnectedTo(this._getConnectedElement()) + const strategy = createFlexibleConnectedPositionStrategy( + this._injector, + this._getConnectedElement(), + ) .withFlexibleDimensions(false) .withPush(false); diff --git a/src/material/autocomplete/autocomplete.spec.ts b/src/material/autocomplete/autocomplete.spec.ts index 126b9ec7c9eb..2370dcd377a8 100644 --- a/src/material/autocomplete/autocomplete.spec.ts +++ b/src/material/autocomplete/autocomplete.spec.ts @@ -1,6 +1,6 @@ import {Directionality} from '@angular/cdk/bidi'; import {DOWN_ARROW, ENTER, ESCAPE, SPACE, TAB, UP_ARROW} from '@angular/cdk/keycodes'; -import {Overlay, OverlayContainer, OverlayModule} from '@angular/cdk/overlay'; +import {createCloseScrollStrategy, OverlayContainer, OverlayModule} from '@angular/cdk/overlay'; import {_supportsShadowDom} from '@angular/cdk/platform'; import {ScrollDispatcher} from '@angular/cdk/scrolling'; import { @@ -16,6 +16,7 @@ import { ChangeDetectionStrategy, Component, ElementRef, + Injector, OnDestroy, OnInit, Provider, @@ -3203,8 +3204,7 @@ describe('MatAutocomplete', () => { }, { provide: MAT_AUTOCOMPLETE_SCROLL_STRATEGY, - useFactory: (overlay: Overlay) => () => overlay.scrollStrategies.close(), - deps: [Overlay], + useFactory: () => () => createCloseScrollStrategy(TestBed.inject(Injector)), }, ]); diff --git a/src/material/bottom-sheet/bottom-sheet.ts b/src/material/bottom-sheet/bottom-sheet.ts index ce8e459e5f0d..2edd0b25574b 100644 --- a/src/material/bottom-sheet/bottom-sheet.ts +++ b/src/material/bottom-sheet/bottom-sheet.ts @@ -7,9 +7,9 @@ */ import {Dialog} from '@angular/cdk/dialog'; -import {Overlay} from '@angular/cdk/overlay'; +import {createBlockScrollStrategy, createGlobalPositionStrategy} from '@angular/cdk/overlay'; import {ComponentType} from '@angular/cdk/portal'; -import {Injectable, TemplateRef, InjectionToken, OnDestroy, inject} from '@angular/core'; +import {Injectable, TemplateRef, InjectionToken, OnDestroy, inject, Injector} from '@angular/core'; import {MAT_BOTTOM_SHEET_DATA, MatBottomSheetConfig} from './bottom-sheet-config'; import {MatBottomSheetContainer} from './bottom-sheet-container'; import {MatBottomSheetRef} from './bottom-sheet-ref'; @@ -25,7 +25,7 @@ export const MAT_BOTTOM_SHEET_DEFAULT_OPTIONS = new InjectionToken(MAT_BOTTOM_SHEET_DEFAULT_OPTIONS, { @@ -89,8 +89,10 @@ export class MatBottomSheet implements OnDestroy { closeOnOverlayDetachments: false, maxWidth: '100%', container: MatBottomSheetContainer, - scrollStrategy: _config.scrollStrategy || this._overlay.scrollStrategies.block(), - positionStrategy: this._overlay.position().global().centerHorizontally().bottom('0'), + scrollStrategy: _config.scrollStrategy || createBlockScrollStrategy(this._injector), + positionStrategy: createGlobalPositionStrategy(this._injector) + .centerHorizontally() + .bottom('0'), disableAnimations: this._animationsDisabled, templateContext: () => ({bottomSheetRef: ref}), providers: (cdkRef, _cdkConfig, container) => { diff --git a/src/material/datepicker/datepicker-base.ts b/src/material/datepicker/datepicker-base.ts index b18e4624c95c..18408d50158d 100644 --- a/src/material/datepicker/datepicker-base.ts +++ b/src/material/datepicker/datepicker-base.ts @@ -21,8 +21,12 @@ import { UP_ARROW, } from '@angular/cdk/keycodes'; import { + createBlockScrollStrategy, + createFlexibleConnectedPositionStrategy, + createGlobalPositionStrategy, + createOverlayRef, + createRepositionScrollStrategy, FlexibleConnectedPositionStrategy, - Overlay, OverlayConfig, OverlayRef, ScrollStrategy, @@ -82,8 +86,8 @@ export const MAT_DATEPICKER_SCROLL_STRATEGY = new InjectionToken<() => ScrollStr { providedIn: 'root', factory: () => { - const overlay = inject(Overlay); - return () => overlay.scrollStrategies.reposition(); + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector); }, }, ); @@ -93,8 +97,9 @@ export const MAT_DATEPICKER_SCROLL_STRATEGY = new InjectionToken<() => ScrollStr * @deprecated No longer used, will be removed. * @breaking-change 21.0.0 */ -export function MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy { - return () => overlay.scrollStrategies.reposition(); +export function MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY(_overlay: unknown): () => ScrollStrategy { + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector); } /** Possible positions for the datepicker dropdown along the X axis. */ @@ -110,7 +115,7 @@ export type DatepickerDropdownPositionY = 'above' | 'below'; */ export const MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER = { provide: MAT_DATEPICKER_SCROLL_STRATEGY, - deps: [Overlay], + deps: [] as any[], useFactory: MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY, }; @@ -390,7 +395,7 @@ export abstract class MatDatepickerBase< > implements MatDatepickerPanel, OnDestroy, OnChanges { - private _overlay = inject(Overlay); + private _injector = inject(Injector); private _viewContainerRef = inject(ViewContainerRef); private _dateAdapter = inject>(DateAdapter, {optional: true})!; private _dir = inject(Directionality, {optional: true}); @@ -565,8 +570,6 @@ export abstract class MatDatepickerBase< /** Emits when the datepicker's state changes. */ readonly stateChanges = new Subject(); - private _injector = inject(Injector); - private readonly _changeDetectorRef = inject(ChangeDetectorRef); constructor(...args: unknown[]); @@ -760,7 +763,8 @@ export abstract class MatDatepickerBase< MatDatepickerContent, this._viewContainerRef, ); - const overlayRef = (this._overlayRef = this._overlay.create( + const overlayRef = (this._overlayRef = createOverlayRef( + this._injector, new OverlayConfig({ positionStrategy: isDialog ? this._getDialogStrategy() : this._getDropdownStrategy(), hasBackdrop: true, @@ -769,7 +773,9 @@ export abstract class MatDatepickerBase< this._backdropHarnessClass, ], direction: this._dir || 'ltr', - scrollStrategy: isDialog ? this._overlay.scrollStrategies.block() : this._scrollStrategy(), + scrollStrategy: isDialog + ? createBlockScrollStrategy(this._injector) + : this._scrollStrategy(), panelClass: `mat-datepicker-${isDialog ? 'dialog' : 'popup'}`, disableAnimations: this._animationsDisabled, }), @@ -825,14 +831,15 @@ export abstract class MatDatepickerBase< /** Gets a position strategy that will open the calendar as a dropdown. */ private _getDialogStrategy() { - return this._overlay.position().global().centerHorizontally().centerVertically(); + return createGlobalPositionStrategy(this._injector).centerHorizontally().centerVertically(); } /** Gets a position strategy that will open the calendar as a dropdown. */ private _getDropdownStrategy() { - const strategy = this._overlay - .position() - .flexibleConnectedTo(this.datepickerInput.getConnectedOverlayOrigin()) + const strategy = createFlexibleConnectedPositionStrategy( + this._injector, + this.datepickerInput.getConnectedOverlayOrigin(), + ) .withTransformOriginOn('.mat-datepicker-content') .withFlexibleDimensions(false) .withViewportMargin(8) diff --git a/src/material/datepicker/datepicker.spec.ts b/src/material/datepicker/datepicker.spec.ts index 1b4675bf3705..5991d9cc51cd 100644 --- a/src/material/datepicker/datepicker.spec.ts +++ b/src/material/datepicker/datepicker.spec.ts @@ -9,7 +9,7 @@ import { RIGHT_ARROW, UP_ARROW, } from '@angular/cdk/keycodes'; -import {Overlay} from '@angular/cdk/overlay'; +import {createCloseScrollStrategy} from '@angular/cdk/overlay'; import {_supportsShadowDom} from '@angular/cdk/platform'; import {ScrollDispatcher} from '@angular/cdk/scrolling'; import { @@ -20,7 +20,15 @@ import { dispatchMouseEvent, typeInElement, } from '@angular/cdk/testing/private'; -import {Component, Directive, Provider, Type, ViewChild, ViewEncapsulation} from '@angular/core'; +import { + Component, + Directive, + Injector, + Provider, + Type, + ViewChild, + ViewEncapsulation, +} from '@angular/core'; import {ComponentFixture, TestBed, fakeAsync, flush, tick} from '@angular/core/testing'; import { FormControl, @@ -508,8 +516,7 @@ describe('MatDatepicker', () => { }, { provide: MAT_DATEPICKER_SCROLL_STRATEGY, - deps: [Overlay], - useFactory: (overlay: Overlay) => () => overlay.scrollStrategies.close(), + useFactory: () => () => createCloseScrollStrategy(TestBed.inject(Injector)), }, ], ); diff --git a/src/material/dialog/dialog.spec.ts b/src/material/dialog/dialog.spec.ts index a043ddfda090..96bbb691f6c5 100644 --- a/src/material/dialog/dialog.spec.ts +++ b/src/material/dialog/dialog.spec.ts @@ -1,7 +1,7 @@ import {FocusMonitor, FocusOrigin} from '@angular/cdk/a11y'; import {Directionality} from '@angular/cdk/bidi'; import {A, ESCAPE} from '@angular/cdk/keycodes'; -import {Overlay, OverlayContainer, ScrollStrategy} from '@angular/cdk/overlay'; +import {createCloseScrollStrategy, OverlayContainer, ScrollStrategy} from '@angular/cdk/overlay'; import {_supportsShadowDom} from '@angular/cdk/platform'; import {ScrollDispatcher} from '@angular/cdk/scrolling'; import { @@ -238,10 +238,9 @@ describe('MatDialog', () => { })); it('should dispatch the beforeClosed and afterClosed events when the overlay is detached externally', fakeAsync(() => { - const overlay = TestBed.inject(Overlay); const dialogRef = dialog.open(PizzaMsg, { viewContainerRef: testViewContainerRef, - scrollStrategy: overlay.scrollStrategies.close(), + scrollStrategy: createCloseScrollStrategy(TestBed.inject(Injector)), }); const beforeClosedCallback = jasmine.createSpy('beforeClosed callback'); const afterCloseCallback = jasmine.createSpy('afterClosed callback'); diff --git a/src/material/dialog/dialog.ts b/src/material/dialog/dialog.ts index ac1a8890a352..1452db39b75e 100644 --- a/src/material/dialog/dialog.ts +++ b/src/material/dialog/dialog.ts @@ -6,11 +6,17 @@ * found in the LICENSE file at https://angular.dev/license */ -import {ComponentType, Overlay, ScrollStrategy} from '@angular/cdk/overlay'; +import { + ComponentType, + createBlockScrollStrategy, + createGlobalPositionStrategy, + ScrollStrategy, +} from '@angular/cdk/overlay'; import { ComponentRef, Injectable, InjectionToken, + Injector, OnDestroy, TemplateRef, Type, @@ -39,8 +45,8 @@ export const MAT_DIALOG_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrateg { providedIn: 'root', factory: () => { - const overlay = inject(Overlay); - return () => overlay.scrollStrategies.block(); + const injector = inject(Injector); + return () => createBlockScrollStrategy(injector); }, }, ); @@ -50,11 +56,11 @@ export const MAT_DIALOG_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrateg */ @Injectable({providedIn: 'root'}) export class MatDialog implements OnDestroy { - private _overlay = inject(Overlay); private _defaultOptions = inject(MAT_DIALOG_DEFAULT_OPTIONS, {optional: true}); private _scrollStrategy = inject(MAT_DIALOG_SCROLL_STRATEGY); private _parentDialog = inject(MatDialog, {optional: true, skipSelf: true}); private _idGenerator = inject(_IdGenerator); + private _injector = inject(Injector); protected _dialog = inject(Dialog); private _animationsDisabled = _animationsDisabled(); @@ -138,7 +144,9 @@ export class MatDialog implements OnDestroy { const cdkRef = this._dialog.open(componentOrTemplateRef, { ...config, - positionStrategy: this._overlay.position().global().centerHorizontally().centerVertically(), + positionStrategy: createGlobalPositionStrategy(this._injector) + .centerHorizontally() + .centerVertically(), // Disable closing since we need to sync it up to the animation ourselves. disableClose: true, // Closing is tied to our animation so the close predicate has to be implemented separately. diff --git a/src/material/menu/menu-trigger.ts b/src/material/menu/menu-trigger.ts index 7fd5a475d9bf..753ec907c611 100644 --- a/src/material/menu/menu-trigger.ts +++ b/src/material/menu/menu-trigger.ts @@ -15,9 +15,11 @@ import { import {Direction, Directionality} from '@angular/cdk/bidi'; import {ENTER, LEFT_ARROW, RIGHT_ARROW, SPACE} from '@angular/cdk/keycodes'; import { + createFlexibleConnectedPositionStrategy, + createOverlayRef, + createRepositionScrollStrategy, FlexibleConnectedPositionStrategy, HorizontalConnectionPos, - Overlay, OverlayConfig, OverlayRef, ScrollStrategy, @@ -32,6 +34,7 @@ import { EventEmitter, inject, InjectionToken, + Injector, Input, NgZone, OnDestroy, @@ -54,8 +57,8 @@ export const MAT_MENU_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrategy> { providedIn: 'root', factory: () => { - const overlay = inject(Overlay); - return () => overlay.scrollStrategies.reposition(); + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector); }, }, ); @@ -65,8 +68,9 @@ export const MAT_MENU_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrategy> * @deprecated No longer used, will be removed. * @breaking-change 21.0.0 */ -export function MAT_MENU_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy { - return () => overlay.scrollStrategies.reposition(); +export function MAT_MENU_SCROLL_STRATEGY_FACTORY(_overlay: unknown): () => ScrollStrategy { + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector); } /** @@ -76,13 +80,10 @@ export function MAT_MENU_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => Scroll */ export const MAT_MENU_SCROLL_STRATEGY_FACTORY_PROVIDER = { provide: MAT_MENU_SCROLL_STRATEGY, - deps: [Overlay], + deps: [] as any[], useFactory: MAT_MENU_SCROLL_STRATEGY_FACTORY, }; -/** Options for binding a passive event listener. */ -const passiveEventListenerOptions = {passive: true}; - /** * Default top padding of the menu panel. * @deprecated No longer being used. Will be removed. @@ -108,13 +109,13 @@ const PANELS_TO_TRIGGERS = new WeakMap(); exportAs: 'matMenuTrigger', }) export class MatMenuTrigger implements AfterContentInit, OnDestroy { - private _overlay = inject(Overlay); private _element = inject>(ElementRef); private _viewContainerRef = inject(ViewContainerRef); private _menuItemInstance = inject(MatMenuItem, {optional: true, self: true})!; private _dir = inject(Directionality, {optional: true}); private _focusMonitor = inject(FocusMonitor); private _ngZone = inject(NgZone); + private _injector = inject(Injector); private _scrollStrategy = inject(MAT_MENU_SCROLL_STRATEGY); private _changeDetectorRef = inject(ChangeDetectorRef); private _animationsDisabled = _animationsDisabled(); @@ -235,7 +236,7 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy { this._openedBy = 'touch'; } }, - passiveEventListenerOptions, + {passive: true}, ); } @@ -420,7 +421,7 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy { menu, config.positionStrategy as FlexibleConnectedPositionStrategy, ); - this._overlayRef = this._overlay.create(config); + this._overlayRef = createOverlayRef(this._injector, config); this._overlayRef.keydownEvents().subscribe(event => { if (this.menu instanceof MatMenu) { this.menu._handleKeydown(event); @@ -437,9 +438,7 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy { */ private _getOverlayConfig(menu: MatMenuPanel): OverlayConfig { return new OverlayConfig({ - positionStrategy: this._overlay - .position() - .flexibleConnectedTo(this._element) + positionStrategy: createFlexibleConnectedPositionStrategy(this._injector, this._element) .withLockedPosition() .withGrowAfterOpen() .withTransformOriginOn('.mat-menu-panel, .mat-mdc-menu-panel'), diff --git a/src/material/menu/menu.spec.ts b/src/material/menu/menu.spec.ts index d9920dcaefb4..cebabbc76fcb 100644 --- a/src/material/menu/menu.spec.ts +++ b/src/material/menu/menu.spec.ts @@ -10,7 +10,7 @@ import { RIGHT_ARROW, TAB, } from '@angular/cdk/keycodes'; -import {Overlay, OverlayContainer} from '@angular/cdk/overlay'; +import {createCloseScrollStrategy, OverlayContainer} from '@angular/cdk/overlay'; import {ScrollDispatcher, ViewportRuler} from '@angular/cdk/scrolling'; import { ChangeDetectionStrategy, @@ -18,6 +18,7 @@ import { Directive, ElementRef, EventEmitter, + Injector, Input, OnDestroy, Output, @@ -775,8 +776,7 @@ describe('MatMenu', () => { {provide: ScrollDispatcher, useFactory: () => ({scrolled: () => scrolledSubject})}, { provide: MAT_MENU_SCROLL_STRATEGY, - deps: [Overlay], - useFactory: (overlay: Overlay) => () => overlay.scrollStrategies.close(), + useFactory: () => () => createCloseScrollStrategy(TestBed.inject(Injector)), }, ], [FakeIcon], diff --git a/src/material/select/select.spec.ts b/src/material/select/select.spec.ts index 45ec3faa501a..1c30d8cfe89a 100644 --- a/src/material/select/select.spec.ts +++ b/src/material/select/select.spec.ts @@ -15,7 +15,7 @@ import { TAB, UP_ARROW, } from '@angular/cdk/keycodes'; -import {CloseScrollStrategy, Overlay, OverlayContainer, OverlayModule} from '@angular/cdk/overlay'; +import {createCloseScrollStrategy, OverlayContainer, OverlayModule} from '@angular/cdk/overlay'; import {ScrollDispatcher} from '@angular/cdk/scrolling'; import { createKeyboardEvent, @@ -30,6 +30,7 @@ import { Component, DebugElement, ElementRef, + Injector, OnInit, Provider, QueryList, @@ -1779,9 +1780,7 @@ describe('MatSelect', () => { providers: [ { provide: MAT_SELECT_SCROLL_STRATEGY, - useFactory: (overlay: Overlay) => (): CloseScrollStrategy => - overlay.scrollStrategies.close(), - deps: [Overlay], + useFactory: () => () => createCloseScrollStrategy(TestBed.inject(Injector)), }, { provide: ScrollDispatcher, diff --git a/src/material/select/select.ts b/src/material/select/select.ts index cc803bf7ab89..4179e0d22544 100644 --- a/src/material/select/select.ts +++ b/src/material/select/select.ts @@ -30,7 +30,7 @@ import { CdkConnectedOverlay, CdkOverlayOrigin, ConnectedPosition, - Overlay, + createRepositionScrollStrategy, ScrollStrategy, } from '@angular/cdk/overlay'; import {ViewportRuler} from '@angular/cdk/scrolling'; @@ -60,6 +60,7 @@ import { ViewEncapsulation, HostAttributeToken, Renderer2, + Injector, } from '@angular/core'; import { AbstractControl, @@ -97,8 +98,8 @@ export const MAT_SELECT_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrateg { providedIn: 'root', factory: () => { - const overlay = inject(Overlay); - return () => overlay.scrollStrategies.reposition(); + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector); }, }, ); @@ -109,9 +110,10 @@ export const MAT_SELECT_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrateg * @breaking-change 21.0.0 */ export function MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY( - overlay: Overlay, + _overlay: unknown, ): () => ScrollStrategy { - return () => overlay.scrollStrategies.reposition(); + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector); } /** Object that can be used to configure the default options for the select module. */ @@ -151,7 +153,7 @@ export const MAT_SELECT_CONFIG = new InjectionToken('MAT_SELECT */ export const MAT_SELECT_SCROLL_STRATEGY_PROVIDER = { provide: MAT_SELECT_SCROLL_STRATEGY, - deps: [Overlay], + deps: [] as any[], useFactory: MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY, }; diff --git a/src/material/snack-bar/snack-bar.ts b/src/material/snack-bar/snack-bar.ts index c7e65e3e2b83..0b42da9d7a09 100644 --- a/src/material/snack-bar/snack-bar.ts +++ b/src/material/snack-bar/snack-bar.ts @@ -8,7 +8,13 @@ import {LiveAnnouncer} from '@angular/cdk/a11y'; import {BreakpointObserver, Breakpoints} from '@angular/cdk/layout'; -import {ComponentType, Overlay, OverlayConfig, OverlayRef} from '@angular/cdk/overlay'; +import { + ComponentType, + createGlobalPositionStrategy, + createOverlayRef, + OverlayConfig, + OverlayRef, +} from '@angular/cdk/overlay'; import { ComponentRef, EmbeddedViewRef, @@ -50,7 +56,6 @@ export const MAT_SNACK_BAR_DEFAULT_OPTIONS = new InjectionToken { @@ -463,10 +463,7 @@ describe('MatTimepicker', () => { }, { provide: MAT_TIMEPICKER_SCROLL_STRATEGY, - useFactory: () => { - const overlay = inject(Overlay); - return () => overlay.scrollStrategies.close(); - }, + useFactory: () => () => createCloseScrollStrategy(TestBed.inject(Injector)), }, ]); diff --git a/src/material/timepicker/timepicker.ts b/src/material/timepicker/timepicker.ts index 7fc2352618e6..ab63291c9699 100644 --- a/src/material/timepicker/timepicker.ts +++ b/src/material/timepicker/timepicker.ts @@ -42,7 +42,13 @@ import { MatOptionParentComponent, } from '../core'; import {Directionality} from '@angular/cdk/bidi'; -import {Overlay, OverlayRef, ScrollStrategy} from '@angular/cdk/overlay'; +import { + createFlexibleConnectedPositionStrategy, + createOverlayRef, + createRepositionScrollStrategy, + OverlayRef, + ScrollStrategy, +} from '@angular/cdk/overlay'; import {TemplatePortal} from '@angular/cdk/portal'; import {_getEventTarget} from '@angular/cdk/platform'; import {ENTER, ESCAPE, hasModifierKey, TAB} from '@angular/cdk/keycodes'; @@ -69,8 +75,8 @@ export const MAT_TIMEPICKER_SCROLL_STRATEGY = new InjectionToken<() => ScrollStr { providedIn: 'root', factory: () => { - const overlay = inject(Overlay); - return () => overlay.scrollStrategies.reposition(); + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector); }, }, ); @@ -95,7 +101,6 @@ export const MAT_TIMEPICKER_SCROLL_STRATEGY = new InjectionToken<() => ScrollStr ], }) export class MatTimepicker implements OnDestroy, MatOptionParentComponent { - private _overlay = inject(Overlay); private _dir = inject(Directionality, {optional: true}); private _viewContainerRef = inject(ViewContainerRef); private _injector = inject(Injector); @@ -316,9 +321,10 @@ export class MatTimepicker implements OnDestroy, MatOptionParentComponent { return this._overlayRef; } - const positionStrategy = this._overlay - .position() - .flexibleConnectedTo(this._input()!.getOverlayOrigin()) + const positionStrategy = createFlexibleConnectedPositionStrategy( + this._injector, + this._input()!.getOverlayOrigin(), + ) .withFlexibleDimensions(false) .withPush(false) .withTransformOriginOn('.mat-timepicker-panel') @@ -338,7 +344,7 @@ export class MatTimepicker implements OnDestroy, MatOptionParentComponent { }, ]); - this._overlayRef = this._overlay.create({ + this._overlayRef = createOverlayRef(this._injector, { positionStrategy, scrollStrategy: this._scrollStrategyFactory(), direction: this._dir || 'ltr', diff --git a/src/material/tooltip/tooltip.ts b/src/material/tooltip/tooltip.ts index d54c7221cdb0..55e3e3e42272 100644 --- a/src/material/tooltip/tooltip.ts +++ b/src/material/tooltip/tooltip.ts @@ -39,10 +39,12 @@ import {Directionality} from '@angular/cdk/bidi'; import { ConnectedPosition, ConnectionPositionPair, + createFlexibleConnectedPositionStrategy, + createOverlayRef, + createRepositionScrollStrategy, FlexibleConnectedPositionStrategy, HorizontalConnectionPos, OriginConnectionPosition, - Overlay, OverlayConnectionPosition, OverlayRef, ScrollDispatcher, @@ -82,8 +84,8 @@ export const MAT_TOOLTIP_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrate { providedIn: 'root', factory: () => { - const overlay = inject(Overlay); - return () => overlay.scrollStrategies.reposition({scrollThrottle: SCROLL_THROTTLE_MS}); + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector, {scrollThrottle: SCROLL_THROTTLE_MS}); }, }, ); @@ -93,8 +95,9 @@ export const MAT_TOOLTIP_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrate * @deprecated No longer used, will be removed. * @breaking-change 21.0.0 */ -export function MAT_TOOLTIP_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy { - return () => overlay.scrollStrategies.reposition({scrollThrottle: SCROLL_THROTTLE_MS}); +export function MAT_TOOLTIP_SCROLL_STRATEGY_FACTORY(_overlay: unknown): () => ScrollStrategy { + const injector = inject(Injector); + return () => createRepositionScrollStrategy(injector, {scrollThrottle: SCROLL_THROTTLE_MS}); } /** @@ -104,7 +107,7 @@ export function MAT_TOOLTIP_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => Scr */ export const MAT_TOOLTIP_SCROLL_STRATEGY_FACTORY_PROVIDER = { provide: MAT_TOOLTIP_SCROLL_STRATEGY, - deps: [Overlay], + deps: [] as any[], useFactory: MAT_TOOLTIP_SCROLL_STRATEGY_FACTORY, }; @@ -525,13 +528,13 @@ export class MatTooltip implements OnDestroy, AfterViewInit { .get(ScrollDispatcher) .getAncestorScrollContainers(this._elementRef); - const overlay = this._injector.get(Overlay); const panelClass = `${this._cssClassPrefix}-${PANEL_CLASS}`; // Create connected position strategy that listens for scroll events to reposition. - const strategy = overlay - .position() - .flexibleConnectedTo(this.positionAtOrigin ? origin || this._elementRef : this._elementRef) + const strategy = createFlexibleConnectedPositionStrategy( + this._injector, + this.positionAtOrigin ? origin || this._elementRef : this._elementRef, + ) .withTransformOriginOn(`.${this._cssClassPrefix}-tooltip`) .withFlexibleDimensions(false) .withViewportMargin(this._viewportMargin) @@ -549,7 +552,7 @@ export class MatTooltip implements OnDestroy, AfterViewInit { } }); - this._overlayRef = overlay.create({ + this._overlayRef = createOverlayRef(this._injector, { direction: this._dir, positionStrategy: strategy, panelClass: this._overlayPanelClass ? [...this._overlayPanelClass, panelClass] : panelClass,