@@ -23,18 +23,8 @@ interface CloseWatcherOptions {
23
23
}
24
24
25
25
type TriggerType = 'hover' | 'focus' | 'click' | 'manual' ;
26
-
27
- type LastOf < T > = UnionToIntersection < T extends any ? ( ) => T : never > extends ( ) => infer R ? R : never ;
28
- type Push < T extends any [ ] , V > = [ ...T , V ] ;
29
- type UnionToIntersection < U > = ( U extends any ? ( k : U ) => void : never ) extends ( k : infer I ) => void ? I : never ;
30
-
31
- type TriggerCombinationHelper < T extends TriggerType , U extends TriggerType [ ] = [ ] > = {
32
- [ K in T ] : K extends LastOf < U >
33
- ? TriggerCombinationHelper < Exclude < T , K > , Push < U , K > >
34
- : `${U extends [ ] ? '' : `${U [ number ] } `} ${K } ` | TriggerCombinationHelper < Exclude < T , K > , Push < U , K > > ;
35
- } [ T ] ;
36
-
37
- type Triggers = TriggerCombinationHelper < TriggerType > ;
26
+ type Combine < T extends string , U extends string = T > = T extends any ? T | `${T } ${Combine < Exclude < U , T > > } ` : never ;
27
+ type Triggers = Combine < TriggerType > ;
38
28
39
29
declare global {
40
30
interface HTMLElementTagNameMap {
@@ -247,24 +237,23 @@ export class GlPopover extends GlElement {
247
237
248
238
private handleTriggerBlur = ( e : FocusEvent ) => {
249
239
if ( this . open && this . hasTrigger ( 'focus' ) ) {
250
- const composedPath = e . composedPath ( ) ;
251
- if ( composedPath . includes ( this ) ) return ;
240
+ if ( e . relatedTarget && this . contains ( e . relatedTarget as Node ) ) return ;
252
241
253
242
void this . hide ( ) ;
254
243
}
255
244
} ;
256
245
257
246
private handleTriggerClick = ( ) => {
258
247
if ( this . hasTrigger ( 'click' ) ) {
259
- if ( this . open ) {
248
+ if ( this . open && this . _triggeredBy !== 'hover' ) {
260
249
if ( this . _skipHideOnClick ) {
261
250
this . _skipHideOnClick = false ;
262
251
return ;
263
252
}
264
253
265
254
void this . hide ( ) ;
266
255
} else {
267
- void this . show ( ) ;
256
+ void this . show ( 'click' ) ;
268
257
}
269
258
}
270
259
} ;
@@ -280,7 +269,11 @@ export class GlPopover extends GlElement {
280
269
281
270
private handleTriggerFocus = ( ) => {
282
271
if ( this . hasTrigger ( 'focus' ) ) {
283
- void this . show ( ) ;
272
+ if ( this . open && this . _triggeredBy !== 'hover' && ! this . hasPopupFocus ( ) ) {
273
+ void this . hide ( ) ;
274
+ } else {
275
+ void this . show ( 'focus' ) ;
276
+ }
284
277
}
285
278
} ;
286
279
@@ -303,12 +296,19 @@ export class GlPopover extends GlElement {
303
296
void this . hide ( ) ;
304
297
} ;
305
298
299
+ private handleWebviewMouseDown = ( e : MouseEvent ) => {
300
+ const composedPath = e . composedPath ( ) ;
301
+ if ( ! composedPath . includes ( this ) ) {
302
+ void this . hide ( ) ;
303
+ }
304
+ } ;
305
+
306
306
private handleMouseOver = ( ) => {
307
307
if ( this . hasTrigger ( 'hover' ) ) {
308
308
clearTimeout ( this . hoverTimeout ) ;
309
309
310
310
const delay = parseDuration ( getComputedStyle ( this ) . getPropertyValue ( '--show-delay' ) ) ;
311
- this . hoverTimeout = setTimeout ( ( ) => this . show ( ) , delay ) ;
311
+ this . hoverTimeout = setTimeout ( ( ) => this . show ( 'hover' ) , delay ) ;
312
312
}
313
313
} ;
314
314
@@ -319,7 +319,7 @@ export class GlPopover extends GlElement {
319
319
const composedPath = e . composedPath ( ) ;
320
320
if ( composedPath [ composedPath . length - 2 ] === this ) return ;
321
321
322
- if ( this . hasPopupFocus ( ) ) return ;
322
+ if ( this . hasPopupFocus ( ) || this . _triggeredBy !== 'hover' ) return ;
323
323
324
324
const delay = parseDuration ( getComputedStyle ( this ) . getPropertyValue ( '--hide-delay' ) ) ;
325
325
this . hoverTimeout = setTimeout ( ( ) => this . hide ( ) , delay ) ;
@@ -353,6 +353,10 @@ export class GlPopover extends GlElement {
353
353
document . addEventListener ( 'focusin' , this . handlePopupBlur ) ;
354
354
window . addEventListener ( 'webview-blur' , this . handleWebviewBlur , false ) ;
355
355
356
+ if ( this . hasTrigger ( 'click' ) || this . hasTrigger ( 'focus' ) ) {
357
+ document . addEventListener ( 'mousedown' , this . handleWebviewMouseDown ) ;
358
+ }
359
+
356
360
this . body . hidden = false ;
357
361
this . popup . active = true ;
358
362
this . popup . reposition ( ) ;
@@ -361,6 +365,7 @@ export class GlPopover extends GlElement {
361
365
} else {
362
366
document . removeEventListener ( 'focusin' , this . handlePopupBlur ) ;
363
367
window . removeEventListener ( 'webview-blur' , this . handleWebviewBlur , false ) ;
368
+ document . removeEventListener ( 'mousedown' , this . handleWebviewMouseDown ) ;
364
369
365
370
// Hide
366
371
@@ -390,8 +395,12 @@ export class GlPopover extends GlElement {
390
395
}
391
396
}
392
397
398
+ private _triggeredBy : TriggerType | undefined ;
393
399
/** Shows the popover. */
394
- async show ( ) {
400
+ async show ( triggeredBy ?: TriggerType ) {
401
+ if ( this . _triggeredBy == null || triggeredBy !== 'hover' ) {
402
+ this . _triggeredBy = triggeredBy ;
403
+ }
395
404
if ( this . open ) return undefined ;
396
405
397
406
this . open = true ;
@@ -400,6 +409,7 @@ export class GlPopover extends GlElement {
400
409
401
410
/** Hides the popover */
402
411
async hide ( ) {
412
+ this . _triggeredBy = undefined ;
403
413
if ( ! this . open ) return undefined ;
404
414
405
415
this . open = false ;
0 commit comments