@@ -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
@@ -988,7 +994,7 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
988
994
*/
989
995
private _getScrollVisibility ( ) : ScrollingVisibility {
990
996
// Note: needs fresh rects since the position could've changed.
991
- const originBounds = this . _origin . getBoundingClientRect ( ) ;
997
+ const originBounds = this . _getOriginRect ( ) ;
992
998
const overlayBounds = this . _pane . getBoundingClientRect ( ) ;
993
999
994
1000
// TODO(jelbourn): instead of needing all of the client rects for these scrolling containers
@@ -1090,6 +1096,29 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
1090
1096
this . _appliedPanelClasses = [ ] ;
1091
1097
}
1092
1098
}
1099
+
1100
+ /** Returns the ClientRect of the current origin. */
1101
+ private _getOriginRect ( ) : ClientRect {
1102
+ const origin = this . _origin ;
1103
+
1104
+ if ( origin instanceof ElementRef ) {
1105
+ return origin . nativeElement . getBoundingClientRect ( ) ;
1106
+ }
1107
+
1108
+ if ( origin instanceof HTMLElement ) {
1109
+ return origin . getBoundingClientRect ( ) ;
1110
+ }
1111
+
1112
+ // If the origin is a point, return a client rect as if it was a 0x0 element at the point.
1113
+ return {
1114
+ top : origin . y ,
1115
+ bottom : origin . y ,
1116
+ left : origin . x ,
1117
+ right : origin . x ,
1118
+ height : 0 ,
1119
+ width : 0
1120
+ } ;
1121
+ }
1093
1122
}
1094
1123
1095
1124
/** A simple (x, y) coordinate. */
0 commit comments