Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 10 additions & 20 deletions goldens/cdk/overlay/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export class BlockScrollStrategy implements ScrollStrategy {
// @public
export class CdkConnectedOverlay implements OnDestroy, OnChanges {
constructor(...args: unknown[]);
asPopover: boolean;
readonly attach: EventEmitter<void>;
attachOverlay(): void;
backdropClass: string | string[];
Expand All @@ -59,8 +58,6 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
minHeight: number | string;
minWidth: number | string;
// (undocumented)
static ngAcceptInputType_asPopover: unknown;
// (undocumented)
static ngAcceptInputType_disposeOnNavigation: unknown;
// (undocumented)
static ngAcceptInputType_flexibleDimensions: unknown;
Expand All @@ -73,6 +70,8 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
// (undocumented)
static ngAcceptInputType_push: unknown;
// (undocumented)
static ngAcceptInputType_usePopover: unknown;
// (undocumented)
ngOnChanges(changes: SimpleChanges): void;
// (undocumented)
ngOnDestroy(): void;
Expand All @@ -92,10 +91,11 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
push: boolean;
scrollStrategy: ScrollStrategy;
transformOriginSelector: string;
usePopover: boolean;
viewportMargin: ViewportMargin;
width: number | string;
// (undocumented)
static ɵdir: i0.ɵɵDirectiveDeclaration<CdkConnectedOverlay, "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", ["cdkConnectedOverlay"], { "origin": { "alias": "cdkConnectedOverlayOrigin"; "required": false; }; "positions": { "alias": "cdkConnectedOverlayPositions"; "required": false; }; "positionStrategy": { "alias": "cdkConnectedOverlayPositionStrategy"; "required": false; }; "offsetX": { "alias": "cdkConnectedOverlayOffsetX"; "required": false; }; "offsetY": { "alias": "cdkConnectedOverlayOffsetY"; "required": false; }; "width": { "alias": "cdkConnectedOverlayWidth"; "required": false; }; "height": { "alias": "cdkConnectedOverlayHeight"; "required": false; }; "minWidth": { "alias": "cdkConnectedOverlayMinWidth"; "required": false; }; "minHeight": { "alias": "cdkConnectedOverlayMinHeight"; "required": false; }; "backdropClass": { "alias": "cdkConnectedOverlayBackdropClass"; "required": false; }; "panelClass": { "alias": "cdkConnectedOverlayPanelClass"; "required": false; }; "viewportMargin": { "alias": "cdkConnectedOverlayViewportMargin"; "required": false; }; "scrollStrategy": { "alias": "cdkConnectedOverlayScrollStrategy"; "required": false; }; "open": { "alias": "cdkConnectedOverlayOpen"; "required": false; }; "disableClose": { "alias": "cdkConnectedOverlayDisableClose"; "required": false; }; "transformOriginSelector": { "alias": "cdkConnectedOverlayTransformOriginOn"; "required": false; }; "hasBackdrop": { "alias": "cdkConnectedOverlayHasBackdrop"; "required": false; }; "lockPosition": { "alias": "cdkConnectedOverlayLockPosition"; "required": false; }; "flexibleDimensions": { "alias": "cdkConnectedOverlayFlexibleDimensions"; "required": false; }; "growAfterOpen": { "alias": "cdkConnectedOverlayGrowAfterOpen"; "required": false; }; "push": { "alias": "cdkConnectedOverlayPush"; "required": false; }; "disposeOnNavigation": { "alias": "cdkConnectedOverlayDisposeOnNavigation"; "required": false; }; "asPopover": { "alias": "cdkConnectedOverlayAsPopover"; "required": false; }; }, { "backdropClick": "backdropClick"; "positionChange": "positionChange"; "attach": "attach"; "detach": "detach"; "overlayKeydown": "overlayKeydown"; "overlayOutsideClick": "overlayOutsideClick"; }, never, never, true, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<CdkConnectedOverlay, "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", ["cdkConnectedOverlay"], { "origin": { "alias": "cdkConnectedOverlayOrigin"; "required": false; }; "positions": { "alias": "cdkConnectedOverlayPositions"; "required": false; }; "positionStrategy": { "alias": "cdkConnectedOverlayPositionStrategy"; "required": false; }; "offsetX": { "alias": "cdkConnectedOverlayOffsetX"; "required": false; }; "offsetY": { "alias": "cdkConnectedOverlayOffsetY"; "required": false; }; "width": { "alias": "cdkConnectedOverlayWidth"; "required": false; }; "height": { "alias": "cdkConnectedOverlayHeight"; "required": false; }; "minWidth": { "alias": "cdkConnectedOverlayMinWidth"; "required": false; }; "minHeight": { "alias": "cdkConnectedOverlayMinHeight"; "required": false; }; "backdropClass": { "alias": "cdkConnectedOverlayBackdropClass"; "required": false; }; "panelClass": { "alias": "cdkConnectedOverlayPanelClass"; "required": false; }; "viewportMargin": { "alias": "cdkConnectedOverlayViewportMargin"; "required": false; }; "scrollStrategy": { "alias": "cdkConnectedOverlayScrollStrategy"; "required": false; }; "open": { "alias": "cdkConnectedOverlayOpen"; "required": false; }; "disableClose": { "alias": "cdkConnectedOverlayDisableClose"; "required": false; }; "transformOriginSelector": { "alias": "cdkConnectedOverlayTransformOriginOn"; "required": false; }; "hasBackdrop": { "alias": "cdkConnectedOverlayHasBackdrop"; "required": false; }; "lockPosition": { "alias": "cdkConnectedOverlayLockPosition"; "required": false; }; "flexibleDimensions": { "alias": "cdkConnectedOverlayFlexibleDimensions"; "required": false; }; "growAfterOpen": { "alias": "cdkConnectedOverlayGrowAfterOpen"; "required": false; }; "push": { "alias": "cdkConnectedOverlayPush"; "required": false; }; "disposeOnNavigation": { "alias": "cdkConnectedOverlayDisposeOnNavigation"; "required": false; }; "usePopover": { "alias": "cdkConnectedOverlayUsePopover"; "required": false; }; }, { "backdropClick": "backdropClick"; "positionChange": "positionChange"; "attach": "attach"; "detach": "detach"; "overlayKeydown": "overlayKeydown"; "overlayOutsideClick": "overlayOutsideClick"; }, never, never, true, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<CdkConnectedOverlay, never>;
}
Expand Down Expand Up @@ -210,7 +210,7 @@ export function createCloseScrollStrategy(injector: Injector, config?: CloseScro
export function createFlexibleConnectedPositionStrategy(injector: Injector, origin: FlexibleConnectedPositionStrategyOrigin): FlexibleConnectedPositionStrategy;

// @public
export function createGlobalPositionStrategy(_injector: Injector): GlobalPositionStrategy;
export function createGlobalPositionStrategy(injector: Injector): GlobalPositionStrategy;

// @public
export function createNoopScrollStrategy(): NoopScrollStrategy;
Expand All @@ -225,24 +225,17 @@ export function createRepositionScrollStrategy(injector: Injector, config?: Repo
export class FlexibleConnectedPositionStrategy implements PositionStrategy {
constructor(connectedTo: FlexibleConnectedPositionStrategyOrigin, _viewportRuler: ViewportRuler, _document: Document, _platform: Platform, _overlayContainer: OverlayContainer);
apply(): void;
asPopover(isPopover: boolean): this;
attach(overlayRef: OverlayRef): void;
attachBackdrop(backdrop: HTMLElement, host: HTMLElement): boolean;
attachHost(host: HTMLElement): boolean;
createStructure(): {
pane: HTMLDivElement;
host: HTMLDivElement;
} | null;
// (undocumented)
detach(): void;
dispose(): void;
getPopoverInsertionPoint(): Element;
_origin: FlexibleConnectedPositionStrategyOrigin;
positionChanges: Observable<ConnectedOverlayPositionChange>;
get positions(): ConnectionPositionPair[];
_preferredPositions: ConnectionPositionPair[];
reapplyLastPosition(): void;
setOrigin(origin: FlexibleConnectedPositionStrategyOrigin): this;
updateStackingOrder(): boolean;
withDefaultOffsetX(offset: number): this;
withDefaultOffsetY(offset: number): this;
withFlexibleDimensions(flexibleDimensions?: boolean): this;
Expand Down Expand Up @@ -277,6 +270,7 @@ export class FullscreenOverlayContainer extends OverlayContainer implements OnDe

// @public
export class GlobalPositionStrategy implements PositionStrategy {
constructor(injector?: Injector);
apply(): void;
// (undocumented)
attach(overlayRef: OverlayRef): void;
Expand All @@ -285,6 +279,7 @@ export class GlobalPositionStrategy implements PositionStrategy {
centerVertically(offset?: string): this;
dispose(): void;
end(value?: string): this;
getPopoverInsertionPoint(): Element;
// @deprecated
height(value?: string): this;
left(value?: string): this;
Expand Down Expand Up @@ -342,6 +337,7 @@ export class OverlayConfig {
panelClass?: string | string[];
positionStrategy?: PositionStrategy;
scrollStrategy?: ScrollStrategy;
usePopover?: boolean;
width?: number | string;
}

Expand Down Expand Up @@ -470,15 +466,9 @@ export interface OverlaySizeConfig {
export interface PositionStrategy {
apply(): void;
attach(overlayRef: OverlayRef): void;
attachBackdrop?(backdrop: HTMLElement, host: HTMLElement): boolean;
attachHost?(host: HTMLElement): boolean;
createStructure?(): {
pane: HTMLElement;
host: HTMLElement;
} | null;
detach?(): void;
dispose(): void;
updateStackingOrder?(host: HTMLElement): boolean;
getPopoverInsertionPoint?(): Element;
}

// @public
Expand Down
2 changes: 1 addition & 1 deletion goldens/material/select/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ export class MatSelect implements AfterContentInit, OnChanges, OnDestroy, OnInit
ngOnInit(): void;
_onBlur(): void;
_onChange: (value: any) => void;
onContainerClick(): void;
onContainerClick(event: MouseEvent): void;
// (undocumented)
_onFocus(): void;
_onTouched: () => void;
Expand Down
2 changes: 2 additions & 0 deletions goldens/material/timepicker/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export class MatTimepicker<D> implements OnDestroy, MatOptionParentComponent {
readonly disabled: Signal<boolean>;
readonly disableRipple: InputSignalWithTransform<boolean, unknown>;
protected _getAriaLabelledby(): string | null;
// (undocumented)
_getOverlayHost(): HTMLElement | undefined;
protected _handleAnimationEnd(event: AnimationEvent): void;
readonly interval: InputSignalWithTransform<number | null, number | string | null>;
readonly isOpen: Signal<boolean>;
Expand Down
3 changes: 2 additions & 1 deletion src/cdk/dialog/dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,8 @@ export class Dialog implements OnDestroy {
sibling !== overlayContainer &&
sibling.nodeName !== 'SCRIPT' &&
sibling.nodeName !== 'STYLE' &&
!sibling.hasAttribute('aria-live')
!sibling.hasAttribute('aria-live') &&
!sibling.hasAttribute('popover')
) {
this._ariaHiddenElements.set(sibling, sibling.getAttribute('aria-hidden'));
sibling.setAttribute('aria-hidden', 'true');
Expand Down
6 changes: 6 additions & 0 deletions src/cdk/overlay/overlay-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ export class OverlayConfig {
*/
disposeOnNavigation?: boolean = false;

/**
* Whether the overlay should be rendered as a native popover element,
* rather than placing it inside of the overlay container.
*/
usePopover?: boolean = false;

constructor(config?: OverlayConfig) {
if (config) {
// Use `Iterable` instead of `Array` because TypeScript, as of 3.6.3,
Expand Down
8 changes: 4 additions & 4 deletions src/cdk/overlay/overlay-directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
}

/** Whether the connected overlay should be rendered inside a popover element or the overlay container. */
@Input({alias: 'cdkConnectedOverlayAsPopover', transform: booleanAttribute})
asPopover: boolean = false;
@Input({alias: 'cdkConnectedOverlayUsePopover', transform: booleanAttribute})
usePopover: boolean = false;

/** Event emitted when the backdrop is clicked. */
@Output() readonly backdropClick = new EventEmitter<MouseEvent>();
Expand Down Expand Up @@ -331,6 +331,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
scrollStrategy: this.scrollStrategy,
hasBackdrop: this.hasBackdrop,
disposeOnNavigation: this.disposeOnNavigation,
usePopover: this.usePopover,
});

if (this.width || this.width === 0) {
Expand Down Expand Up @@ -380,8 +381,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
.withGrowAfterOpen(this.growAfterOpen)
.withViewportMargin(this.viewportMargin)
.withLockedPosition(this.lockPosition)
.withTransformOriginOn(this.transformOriginSelector)
.asPopover(this.asPopover);
.withTransformOriginOn(this.transformOriginSelector);
}

/** Returns the position strategy of the overlay to be set on the overlay config */
Expand Down
42 changes: 21 additions & 21 deletions src/cdk/overlay/overlay-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,23 +117,11 @@ export class OverlayRef implements PortalOutlet {
attach(portal: Portal<any>): any {
// Insert the host into the DOM before attaching the portal, otherwise
// the animations module will skip animations on repeat attachments.
if (!this._host.parentElement) {
const hasAttachedHost = this._positionStrategy?.attachHost?.(this._host);

if (!hasAttachedHost && this._previousHostParent) {
this._previousHostParent.appendChild(this._host);
}
}
this._attachHost();

const attachResult = this._portalOutlet.attach(portal);
this._positionStrategy?.attach(this);

const hasUpdatedStackingOrder = this._positionStrategy?.updateStackingOrder?.(this._host);

if (!hasUpdatedStackingOrder) {
this._updateStackingOrder();
}

this._updateStackingOrder();
this._updateElementSize();
this._updateElementDirection();

Expand Down Expand Up @@ -415,6 +403,20 @@ export class OverlayRef implements PortalOutlet {
this._pane.style.pointerEvents = enablePointer ? '' : 'none';
}

private _attachHost() {
if (!this._host.parentElement) {
if (this._config.usePopover && this._positionStrategy?.getPopoverInsertionPoint) {
this._positionStrategy.getPopoverInsertionPoint().after(this._host);
} else {
this._previousHostParent?.appendChild(this._host);
}
}

if (this._config.usePopover) {
this._host.showPopover();
}
}

/** Attaches a backdrop for this overlay. */
private _attachBackdrop() {
const showingClass = 'cdk-overlay-backdrop-showing';
Expand All @@ -432,12 +434,10 @@ export class OverlayRef implements PortalOutlet {
this._toggleClasses(this._backdropRef.element, this._config.backdropClass, true);
}

const strategyAttached = this._positionStrategy?.attachBackdrop?.(
this._backdropRef.element,
this._host,
);

if (!strategyAttached) {
if (this._config.usePopover) {
// When using popovers, the backdrop needs to be inside the popover.
this._host.prepend(this._backdropRef.element);
} else {
// Insert the backdrop before the pane in the DOM order,
// in order to handle stacked overlays properly.
this._host.parentElement!.insertBefore(this._backdropRef.element, this._host);
Expand All @@ -461,7 +461,7 @@ export class OverlayRef implements PortalOutlet {
* in its original DOM position.
*/
private _updateStackingOrder() {
if (this._host.nextSibling) {
if (!this._config.usePopover && this._host.nextSibling) {
this._host.parentNode!.appendChild(this._host);
}
}
Expand Down
38 changes: 19 additions & 19 deletions src/cdk/overlay/overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,34 +47,34 @@ export function createOverlayRef(injector: Injector, config?: OverlayConfig): Ov
const idGenerator = injector.get(_IdGenerator);
const appRef = injector.get(ApplicationRef);
const directionality = injector.get(Directionality);
const overlayConfig = new OverlayConfig(config);
const customStructure = overlayConfig.positionStrategy?.createStructure?.();
const renderer =
injector.get(Renderer2, null, {optional: true}) ||
injector.get(RendererFactory2).createRenderer(null, null);

let pane: HTMLElement;
let host: HTMLElement;
const overlayConfig = new OverlayConfig(config);

if (customStructure) {
pane = customStructure.pane;
host = customStructure.host;
} else {
host = doc.createElement('div');
pane = doc.createElement('div');
host.appendChild(pane);
overlayContainer.getContainerElement().appendChild(host);
}
overlayConfig.direction = overlayConfig.direction || directionality.value;
overlayConfig.usePopover = !!overlayConfig?.usePopover && 'showPopover' in doc.body;

const pane = doc.createElement('div');
const host = doc.createElement('div');
pane.id = idGenerator.getId('cdk-overlay-');
pane.classList.add('cdk-overlay-pane');
host.appendChild(pane);

const portalOutlet = new DomPortalOutlet(pane, appRef, injector);
const renderer =
injector.get(Renderer2, null, {optional: true}) ||
injector.get(RendererFactory2).createRenderer(null, null);
if (overlayConfig.usePopover) {
host.setAttribute('popover', 'manual');
host.classList.add('cdk-overlay-popover');
}

overlayConfig.direction = overlayConfig.direction || directionality.value;
if (overlayConfig.usePopover && overlayConfig.positionStrategy?.getPopoverInsertionPoint) {
overlayConfig.positionStrategy.getPopoverInsertionPoint().after(host);
} else {
overlayContainer.getContainerElement().appendChild(host);
}

return new OverlayRef(
portalOutlet,
new DomPortalOutlet(pane, appRef, injector),
host,
pane,
overlayConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2982,7 +2982,7 @@ describe('FlexibleConnectedPositionStrategy', () => {
});

it('should place the overlay inside the overlay container by default', () => {
attachOverlay({positionStrategy});
attachOverlay({positionStrategy, usePopover: false});
expect(containerElement.contains(overlayRef.hostElement)).toBe(true);
expect(overlayRef.hostElement.getAttribute('popover')).toBeFalsy();
});
Expand All @@ -2992,8 +2992,7 @@ describe('FlexibleConnectedPositionStrategy', () => {
return;
}

positionStrategy.asPopover(true);
attachOverlay({positionStrategy});
attachOverlay({positionStrategy, usePopover: true});

expect(containerElement.contains(overlayRef.hostElement)).toBe(false);
expect(originElement.nextElementSibling).toBe(overlayRef.hostElement);
Expand All @@ -3005,8 +3004,7 @@ describe('FlexibleConnectedPositionStrategy', () => {
return;
}

positionStrategy.asPopover(true);
attachOverlay({positionStrategy});
attachOverlay({positionStrategy, usePopover: true});
expect(originElement.nextElementSibling).toBe(overlayRef.hostElement);

overlayRef.detach();
Expand Down
Loading
Loading