Skip to content

Commit 2a54c83

Browse files
committed
feat(cdk/overlay): Add option to insert overlay after an element instead of at root
1 parent e5d76d4 commit 2a54c83

File tree

3 files changed

+30
-3
lines changed

3 files changed

+30
-3
lines changed

src/cdk/overlay/overlay-config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9+
import {ElementRef} from '@angular/core';
910
import {PositionStrategy} from './position/position-strategy';
1011
import {Direction, Directionality} from '../bidi';
1112
import {ScrollStrategy, NoopScrollStrategy} from './scroll/index';
@@ -30,6 +31,9 @@ export class OverlayConfig {
3031
/** Whether to disable any built-in animations. */
3132
disableAnimations?: boolean;
3233

34+
/** If specified, insert overlay after this element, instead of using the global overlay container. */
35+
insertOverlayAfter?: ElementRef;
36+
3337
/** The width of the overlay panel. If a number is provided, pixel units are assumed. */
3438
width?: number | string;
3539

src/cdk/overlay/overlay.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,21 @@ export function createOverlayRef(injector: Injector, config?: OverlayConfig): Ov
4848
const appRef = injector.get(ApplicationRef);
4949
const directionality = injector.get(Directionality);
5050

51+
// Create the overlay pane and a parent which will then be attached to the document.
5152
const host = doc.createElement('div');
5253
const pane = doc.createElement('div');
53-
5454
pane.id = idGenerator.getId('cdk-overlay-');
5555
pane.classList.add('cdk-overlay-pane');
5656
host.appendChild(pane);
57-
overlayContainer.getContainerElement().appendChild(host);
57+
58+
// Insert after the specified element, or onto the global overlay container.
59+
if (config?.insertOverlayAfter) {
60+
const element = config.insertOverlayAfter.nativeElement;
61+
element.after(host);
62+
element.parentElement.style.position = 'relative';
63+
} else {
64+
overlayContainer.getContainerElement().appendChild(host);
65+
}
5866

5967
const portalOutlet = new DomPortalOutlet(pane, appRef, injector);
6068
const overlayConfig = new OverlayConfig(config);

src/cdk/overlay/position/flexible-connected-position-strategy.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,14 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
581581
overlayStartY = pos.overlayY == 'top' ? 0 : -overlayRect.height;
582582
}
583583

584+
// Adjust the overly position when it is placed inline relative to its parent.
585+
const insertOverlayAfter = this._overlayRef.getConfig().insertOverlayAfter;
586+
if (insertOverlayAfter) {
587+
const rect = insertOverlayAfter!.nativeElement.getBoundingClientRect();
588+
overlayStartX -= rect.left;
589+
overlayStartY -= rect.top;
590+
}
591+
584592
// The (x, y) coordinates of the overlay.
585593
return {
586594
x: originPoint.x + overlayStartX,
@@ -889,7 +897,14 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
889897
if (this._hasExactPosition()) {
890898
styles.top = styles.left = '0';
891899
styles.bottom = styles.right = styles.maxHeight = styles.maxWidth = '';
892-
styles.width = styles.height = '100%';
900+
901+
if (this._overlayRef.getConfig().insertOverlayAfter) {
902+
styles.width = coerceCssPixelValue(boundingBoxRect.width);
903+
styles.height = coerceCssPixelValue(boundingBoxRect.height);
904+
} else {
905+
// TODO(andreyd): can most likley remove this for common case
906+
styles.width = styles.height = '100%';
907+
}
893908
} else {
894909
const maxHeight = this._overlayRef.getConfig().maxHeight;
895910
const maxWidth = this._overlayRef.getConfig().maxWidth;

0 commit comments

Comments
 (0)