@@ -8,6 +8,7 @@ import { OverlayController } from '../src/OverlayController.js';
88import { overlays } from '../src/overlays.js' ;
99import { keyCodes } from '../src/utils/key-codes.js' ;
1010import { simulateTab } from '../src/utils/simulate-tab.js' ;
11+ import { mimicClick } from '../test-helpers.js' ;
1112
1213/**
1314 * @typedef {import('../types/OverlayConfig').OverlayConfig } OverlayConfig
@@ -451,8 +452,12 @@ describe('OverlayController', () => {
451452 contentNode,
452453 } ) ;
453454 await ctrl . show ( ) ;
455+ mimicClick ( document . body ) ;
456+ await aTimeout ( 0 ) ;
457+ expect ( ctrl . isShown ) . to . be . false ;
454458
455- document . body . click ( ) ;
459+ await ctrl . show ( ) ;
460+ await mimicClick ( document . body , { isAsync : true } ) ;
456461 await aTimeout ( 0 ) ;
457462 expect ( ctrl . isShown ) . to . be . false ;
458463 } ) ;
@@ -479,13 +484,56 @@ describe('OverlayController', () => {
479484
480485 expect ( ctrl . isShown ) . to . be . true ;
481486
487+ // Don't hide on inside mousedown & outside mouseup
488+ ctrl . contentNode . dispatchEvent ( new MouseEvent ( 'mousedown' ) ) ;
489+ await aTimeout ( 0 ) ;
490+ document . body . dispatchEvent ( new MouseEvent ( 'mouseup' ) ) ;
491+ await aTimeout ( 0 ) ;
492+ expect ( ctrl . isShown ) . to . be . true ;
493+
482494 // Important to check if it can be still shown after, because we do some hacks inside
483495 await ctrl . hide ( ) ;
484496 expect ( ctrl . isShown ) . to . be . false ;
485497 await ctrl . show ( ) ;
486498 expect ( ctrl . isShown ) . to . be . true ;
487499 } ) ;
488500
501+ it ( 'only hides when both mousedown and mouseup events are outside' , async ( ) => {
502+ const contentNode = /** @type {HTMLElement } */ ( await fixture ( '<div>Content</div>' ) ) ;
503+ const ctrl = new OverlayController ( {
504+ ...withGlobalTestConfig ( ) ,
505+ hidesOnOutsideClick : true ,
506+ contentNode,
507+ invokerNode : /** @type {HTMLElement } */ ( fixtureSync ( html `
508+ < div role ="button " style ="width: 100px; height: 20px; "> Invoker</ div >
509+ ` ) ) ,
510+ } ) ;
511+ await ctrl . show ( ) ;
512+ mimicClick ( document . body , { releaseElement : contentNode } ) ;
513+ await aTimeout ( 0 ) ;
514+ expect ( ctrl . isShown ) . to . be . true ;
515+
516+ mimicClick ( contentNode , { releaseElement : document . body } ) ;
517+ await aTimeout ( 0 ) ;
518+ expect ( ctrl . isShown ) . to . be . true ;
519+
520+ mimicClick ( document . body , {
521+ releaseElement : /** @type {HTMLElement } */ ( ctrl . invokerNode ) ,
522+ } ) ;
523+ await aTimeout ( 0 ) ;
524+ expect ( ctrl . isShown ) . to . be . true ;
525+
526+ mimicClick ( /** @type {HTMLElement } */ ( ctrl . invokerNode ) , {
527+ releaseElement : document . body ,
528+ } ) ;
529+ await aTimeout ( 0 ) ;
530+ expect ( ctrl . isShown ) . to . be . true ;
531+
532+ mimicClick ( document . body ) ;
533+ await aTimeout ( 0 ) ;
534+ expect ( ctrl . isShown ) . to . be . false ;
535+ } ) ;
536+
489537 it ( 'doesn\'t hide on "inside sub shadow dom" click' , async ( ) => {
490538 const invokerNode = /** @type {HTMLElement } */ ( await fixture ( '<button>Invoker</button>' ) ) ;
491539 const contentNode = /** @type {HTMLElement } */ ( await fixture ( '<div>Content</div>' ) ) ;
@@ -548,31 +596,24 @@ describe('OverlayController', () => {
548596 contentNode,
549597 invokerNode,
550598 } ) ;
599+ const stopProp = ( /** @type {Event } */ e ) => e . stopPropagation ( ) ;
551600 const dom = await fixture (
552- /**
553- * @param {{ stopPropagation: () => any; } } e
554- */
555601 `
556602 <div>
557603 <div id="popup">${ invokerNode } ${ contentNode } </div>
558- <div
559- id="regular-sibling"
560- @click="${ ( ) => {
561- /* propagates */
562- } } "
563- ></div>
564- <third-party-noise @click="${ ( /** @type {Event } */ e ) => e . stopPropagation ( ) } ">
604+ <div id="third-party-noise" @click="${ stopProp } " @mousedown="${ stopProp } " @mouseup="${ stopProp } ">
565605 This element prevents our handlers from reaching the document click handler.
566- </third-party-noise >
606+ </div >
567607 </div>
568608 ` ,
569609 ) ;
570610
571611 await ctrl . show ( ) ;
572612 expect ( ctrl . isShown ) . to . equal ( true ) ;
573613
574- /** @type {HTMLElement } */
575- ( dom . querySelector ( 'third-party-noise' ) ) . click ( ) ;
614+ const noiseEl = /** @type {HTMLElement } */ ( dom . querySelector ( '#third-party-noise' ) ) ;
615+
616+ mimicClick ( noiseEl ) ;
576617 await aTimeout ( 0 ) ;
577618 expect ( ctrl . isShown ) . to . equal ( false ) ;
578619
@@ -592,35 +633,26 @@ describe('OverlayController', () => {
592633 contentNode,
593634 invokerNode,
594635 } ) ;
636+ const stopProp = ( /** @type {Event } */ e ) => e . stopPropagation ( ) ;
595637 const dom = /** @type {HTMLElement } */ ( await fixture ( `
596638 <div>
597639 <div id="popup">${ invokerNode } ${ ctrl . content } </div>
598- <div
599- id="regular-sibling"
600- @click="${ ( ) => {
601- /* propagates */
602- } } "
603- ></div>
604- <third-party-noise>
640+ <div id="third-party-noise">
605641 This element prevents our handlers from reaching the document click handler.
606- </third-party-noise >
642+ </div >
607643 </div>
608644 ` ) ) ;
609645
610- /** @type {HTMLElement } */
611- ( dom . querySelector ( 'third-party-noise' ) ) . addEventListener (
612- 'click' ,
613- ( /** @type {Event } */ event ) => {
614- event . stopPropagation ( ) ;
615- } ,
616- true ,
617- ) ;
646+ const noiseEl = /** @type {HTMLElement } */ ( dom . querySelector ( '#third-party-noise' ) ) ;
647+
648+ noiseEl . addEventListener ( 'click' , stopProp , true ) ;
649+ noiseEl . addEventListener ( 'mousedown' , stopProp , true ) ;
650+ noiseEl . addEventListener ( 'mouseup' , stopProp , true ) ;
618651
619652 await ctrl . show ( ) ;
620653 expect ( ctrl . isShown ) . to . equal ( true ) ;
621654
622- /** @type {HTMLElement } */
623- ( dom . querySelector ( 'third-party-noise' ) ) . click ( ) ;
655+ mimicClick ( noiseEl ) ;
624656 await aTimeout ( 0 ) ;
625657 expect ( ctrl . isShown ) . to . equal ( false ) ;
626658
0 commit comments