@@ -19,7 +19,7 @@ import {
19
19
import { Observable , Subscription , Subject , Observer } from 'rxjs' ;
20
20
import { OverlayReference } from '../overlay-reference' ;
21
21
import { isElementScrolledOutsideView , isElementClippedByScrolling } from './scroll-clip' ;
22
- import { coerceCssPixelValue , coerceArray , coerceElement } from '@angular/cdk/coercion' ;
22
+ import { coerceCssPixelValue , coerceArray } from '@angular/cdk/coercion' ;
23
23
import { Platform } from '@angular/cdk/platform' ;
24
24
import { OverlayContainer } from '../overlay-container' ;
25
25
@@ -29,6 +29,9 @@ import {OverlayContainer} from '../overlay-container';
29
29
/** Class to be added to the overlay bounding box. */
30
30
const boundingBoxClass = 'cdk-overlay-connected-position-bounding-box' ;
31
31
32
+ /** Possible values that can be set as the origin of a FlexibleConnectedPositionStrategy. */
33
+ export type FlexibleConnectedPositionStrategyOrigin = ElementRef | HTMLElement | Point ;
34
+
32
35
/**
33
36
* A strategy for positioning overlays. Using this strategy, an overlay is given an
34
37
* implicit position relative some origin element. The relative position is defined in terms of
@@ -80,7 +83,7 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
80
83
_preferredPositions : ConnectionPositionPair [ ] = [ ] ;
81
84
82
85
/** The origin element against which the overlay will be positioned. */
83
- private _origin : HTMLElement ;
86
+ private _origin : FlexibleConnectedPositionStrategyOrigin ;
84
87
85
88
/** The overlay pane element. */
86
89
private _pane : HTMLElement ;
@@ -139,7 +142,7 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
139
142
}
140
143
141
144
constructor (
142
- connectedTo : ElementRef | HTMLElement ,
145
+ connectedTo : FlexibleConnectedPositionStrategyOrigin ,
143
146
private _viewportRuler : ViewportRuler ,
144
147
private _document : Document ,
145
148
// @breaking -change 8.0.0 `_platform` and `_overlayContainer` parameters to be made required.
@@ -211,7 +214,7 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
211
214
// the overlay relative to the origin.
212
215
// We use the viewport rect to determine whether a position would go off-screen.
213
216
this . _viewportRect = this . _getNarrowedViewportRect ( ) ;
214
- this . _originRect = this . _origin . getBoundingClientRect ( ) ;
217
+ this . _originRect = this . _getOriginRect ( ) ;
215
218
this . _overlayRect = this . _pane . getBoundingClientRect ( ) ;
216
219
217
220
const originRect = this . _originRect ;
@@ -350,7 +353,7 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
350
353
*/
351
354
reapplyLastPosition ( ) : void {
352
355
if ( ! this . _isDisposed && ( ! this . _platform || this . _platform . isBrowser ) ) {
353
- this . _originRect = this . _origin . getBoundingClientRect ( ) ;
356
+ this . _originRect = this . _getOriginRect ( ) ;
354
357
this . _overlayRect = this . _pane . getBoundingClientRect ( ) ;
355
358
this . _viewportRect = this . _getNarrowedViewportRect ( ) ;
356
359
@@ -427,11 +430,14 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
427
430
}
428
431
429
432
/**
430
- * Sets the origin element, relative to which to position the overlay.
431
- * @param origin Reference to the new origin element.
433
+ * Sets the origin, relative to which to position the overlay.
434
+ * Using an element origin is useful for building components that need to be positioned
435
+ * relatively to a trigger (e.g. dropdown menus or tooltips), whereas using a point can be
436
+ * used for cases like contextual menus which open relative to the user's pointer.
437
+ * @param origin Reference to the new origin.
432
438
*/
433
- setOrigin ( origin : ElementRef | HTMLElement ) : this {
434
- this . _origin = coerceElement ( origin ) ;
439
+ setOrigin ( origin : FlexibleConnectedPositionStrategyOrigin ) : this {
440
+ this . _origin = origin ;
435
441
return this ;
436
442
}
437
443
@@ -987,7 +993,7 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
987
993
*/
988
994
private _getScrollVisibility ( ) : ScrollingVisibility {
989
995
// Note: needs fresh rects since the position could've changed.
990
- const originBounds = this . _origin . getBoundingClientRect ( ) ;
996
+ const originBounds = this . _getOriginRect ( ) ;
991
997
const overlayBounds = this . _pane . getBoundingClientRect ( ) ;
992
998
993
999
// TODO(jelbourn): instead of needing all of the client rects for these scrolling containers
@@ -1089,6 +1095,29 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
1089
1095
this . _appliedPanelClasses = [ ] ;
1090
1096
}
1091
1097
}
1098
+
1099
+ /** Returns the ClientRect of the current origin. */
1100
+ private _getOriginRect ( ) : ClientRect {
1101
+ const origin = this . _origin ;
1102
+
1103
+ if ( origin instanceof ElementRef ) {
1104
+ return origin . nativeElement . getBoundingClientRect ( ) ;
1105
+ }
1106
+
1107
+ if ( origin instanceof HTMLElement ) {
1108
+ return origin . getBoundingClientRect ( ) ;
1109
+ }
1110
+
1111
+ // If the origin is a point, return a client rect as if it was a 0x0 element at the point.
1112
+ return {
1113
+ top : origin . y ,
1114
+ bottom : origin . y ,
1115
+ left : origin . x ,
1116
+ right : origin . x ,
1117
+ height : 0 ,
1118
+ width : 0
1119
+ } ;
1120
+ }
1092
1121
}
1093
1122
1094
1123
/** A simple (x, y) coordinate. */
0 commit comments