11import {
22 type Middleware ,
3+ type MiddlewareData ,
4+ type Placement ,
5+ arrow ,
36 autoUpdate ,
47 computePosition ,
58 flip ,
9+ inline ,
610 limitShift ,
711 offset ,
812 shift ,
@@ -14,6 +18,7 @@ import { property, query, queryAssignedElements } from 'lit/decorators.js';
1418import { watch } from '../common/decorators/watch.js' ;
1519import { registerComponent } from '../common/definitions/register.js' ;
1620import {
21+ first ,
1722 getElementByIdFromRoot ,
1823 isEmpty ,
1924 isString ,
@@ -72,6 +77,19 @@ export default class IgcPopoverComponent extends LitElement {
7277 @property ( )
7378 public anchor ?: Element | string ;
7479
80+ /**
81+ * Element to render as an "arrow" element for the current popover.
82+ */
83+ @property ( { attribute : false } )
84+ public arrow : HTMLElement | null = null ;
85+
86+ /**
87+ * Improves positioning for inline reference elements that span over multiple lines.
88+ * Useful for tooltips or similar components.
89+ */
90+ @property ( { type : Boolean , reflect : true } )
91+ public inline = false ;
92+
7593 /**
7694 * When enabled this changes the placement of the floating element in order to keep it
7795 * in view along the main axis.
@@ -127,7 +145,9 @@ export default class IgcPopoverComponent extends LitElement {
127145 this . open ? this . show ( ) : this . hide ( ) ;
128146 }
129147
148+ @watch ( 'arrow' , { waitUntilFirstUpdate : true } )
130149 @watch ( 'flip' , { waitUntilFirstUpdate : true } )
150+ @watch ( 'inline' , { waitUntilFirstUpdate : true } )
131151 @watch ( 'offset' , { waitUntilFirstUpdate : true } )
132152 @watch ( 'placement' , { waitUntilFirstUpdate : true } )
133153 @watch ( 'sameWidth' , { waitUntilFirstUpdate : true } )
@@ -187,6 +207,10 @@ export default class IgcPopoverComponent extends LitElement {
187207 middleware . push ( offset ( this . offset ) ) ;
188208 }
189209
210+ if ( this . inline ) {
211+ middleware . push ( inline ( ) ) ;
212+ }
213+
190214 if ( this . shift ) {
191215 middleware . push (
192216 shift ( {
@@ -195,6 +219,10 @@ export default class IgcPopoverComponent extends LitElement {
195219 ) ;
196220 }
197221
222+ if ( this . arrow ) {
223+ middleware . push ( arrow ( { element : this . arrow } ) ) ;
224+ }
225+
198226 if ( this . flip ) {
199227 middleware . push ( flip ( ) ) ;
200228 }
@@ -226,17 +254,47 @@ export default class IgcPopoverComponent extends LitElement {
226254 return ;
227255 }
228256
229- const { x, y } = await computePosition ( this . target , this . _container , {
230- placement : this . placement ?? 'bottom-start' ,
231- middleware : this . _createMiddleware ( ) ,
232- strategy : 'fixed' ,
233- } ) ;
257+ const { x, y, middlewareData, placement } = await computePosition (
258+ this . target ,
259+ this . _container ,
260+ {
261+ placement : this . placement ?? 'bottom-start' ,
262+ middleware : this . _createMiddleware ( ) ,
263+ strategy : 'fixed' ,
264+ }
265+ ) ;
234266
235267 Object . assign ( this . _container . style , {
236268 left : 0 ,
237269 top : 0 ,
238270 transform : `translate(${ roundByDPR ( x ) } px,${ roundByDPR ( y ) } px)` ,
239271 } ) ;
272+
273+ this . _positionArrow ( placement , middlewareData ) ;
274+ }
275+
276+ private _positionArrow ( placement : Placement , data : MiddlewareData ) {
277+ if ( ! data . arrow ) {
278+ return ;
279+ }
280+
281+ const { x, y } = data . arrow ;
282+
283+ const staticSide = {
284+ top : 'bottom' ,
285+ right : 'left' ,
286+ bottom : 'top' ,
287+ left : 'right' ,
288+ } [ first ( placement . split ( '-' ) ) ] ! ;
289+
290+ // TODO: Clean-up this stuff
291+ Object . assign ( this . arrow ! . style , {
292+ left : x !== null ? `${ roundByDPR ( x ! ) } px` : '' ,
293+ top : y !== null ? `${ roundByDPR ( y ! ) } px` : '' ,
294+ right : '' ,
295+ bottom : '' ,
296+ [ staticSide ] : '-4px' ,
297+ } ) ;
240298 }
241299
242300 private _anchorSlotChange ( ) {
0 commit comments