@@ -11,7 +11,7 @@ governing permissions and limitations under the License.
1111*/
1212
1313import { ActiveOverlay } from './active-overlay.js' ;
14- import { OverlayOpenDetail , OverlayCloseDetail } from './overlay.js ' ;
14+ import { OverlayOpenDetail } from './overlay-types ' ;
1515
1616function isLeftClick ( event : MouseEvent ) : boolean {
1717 return event . button === 0 ;
@@ -22,19 +22,11 @@ function hasModifier(event: MouseEvent): boolean {
2222}
2323
2424export class OverlayStack {
25- public overlays : ActiveOverlay [ ] = [ ] ;
26-
2725 private preventMouseRootClose = false ;
2826 private root : HTMLElement = document . body ;
29- private onChange : ( overlays : ActiveOverlay [ ] ) => void ;
3027 private handlingResize = false ;
3128
32- public constructor (
33- root : HTMLElement ,
34- onChange : ( overlays : ActiveOverlay [ ] ) => void
35- ) {
36- this . root = root ;
37- this . onChange = onChange ;
29+ public constructor ( ) {
3830 this . addEventListeners ( ) ;
3931 }
4032
@@ -43,7 +35,44 @@ export class OverlayStack {
4335 }
4436
4537 private get topOverlay ( ) : ActiveOverlay | undefined {
46- return this . overlays . slice ( - 1 ) [ 0 ] ;
38+ for (
39+ let index = document . body . children . length - 1 ;
40+ index >= 0 ;
41+ index --
42+ ) {
43+ const element = document . body . children [ index ] ;
44+ if ( element instanceof ActiveOverlay ) {
45+ return element ;
46+ }
47+ }
48+ }
49+
50+ private * overlays ( ) : Generator < ActiveOverlay , void , undefined > {
51+ for ( const item of document . body . children ) {
52+ if ( item instanceof ActiveOverlay ) {
53+ yield item ;
54+ }
55+ }
56+ }
57+
58+ private findOverlayForContent (
59+ overlayContent : HTMLElement
60+ ) : ActiveOverlay | undefined {
61+ for ( const item of this . overlays ( ) ) {
62+ if ( overlayContent . isSameNode ( item . overlayContent as HTMLElement ) ) {
63+ return item ;
64+ }
65+ }
66+ }
67+
68+ private findOverlayForTrigger (
69+ overlayContent : HTMLElement
70+ ) : ActiveOverlay | undefined {
71+ for ( const item of this . overlays ( ) ) {
72+ if ( overlayContent . isSameNode ( item . trigger as HTMLElement ) ) {
73+ return item ;
74+ }
75+ }
4776 }
4877
4978 private addEventListeners ( ) : void {
@@ -54,47 +83,37 @@ export class OverlayStack {
5483 }
5584
5685 private isOverlayActive ( overlayContent : HTMLElement ) : boolean {
57- return ! ! this . overlays . find ( ( item ) =>
58- overlayContent . isSameNode ( item . overlayContent as HTMLElement )
59- ) ;
86+ return ! ! this . findOverlayForContent ( overlayContent ) ;
6087 }
6188
6289 private isClickOverlayActiveForTrigger ( trigger : HTMLElement ) : boolean {
63- return this . overlays . some (
64- ( item ) =>
65- trigger . isSameNode ( item . trigger as HTMLElement ) &&
66- item . interaction === 'click'
67- ) ;
90+ const overlay = this . findOverlayForTrigger ( trigger ) ;
91+ return overlay != null && overlay . interaction === 'click' ;
6892 }
6993
70- public openOverlay ( event : CustomEvent < OverlayOpenDetail > ) : void {
71- if ( this . isOverlayActive ( event . detail . content ) ) return ;
94+ public openOverlay ( details : OverlayOpenDetail ) : void {
95+ /* istanbul ignore if */
96+ if ( this . isOverlayActive ( details . content ) ) return ;
7297
7398 requestAnimationFrame ( ( ) => {
74- const interaction = event . detail . interaction ;
75- if ( interaction === 'click' ) {
99+ if ( details . interaction === 'click' ) {
76100 this . closeAllHoverOverlays ( ) ;
77101 } else if (
78- interaction === 'hover' &&
79- this . isClickOverlayActiveForTrigger ( event . detail . trigger )
102+ details . interaction === 'hover' &&
103+ this . isClickOverlayActiveForTrigger ( details . trigger )
80104 ) {
81105 // Don't show a hover popover if the click popover is already active
82106 return ;
83107 }
84108
85- const activeOverlay = ActiveOverlay . create ( event , this . root ) ;
86- this . overlays . push ( activeOverlay ) ;
87-
88- this . onChange ( this . overlays ) ;
109+ const activeOverlay = ActiveOverlay . create ( details ) ;
110+ document . body . appendChild ( activeOverlay ) ;
89111 } ) ;
90112 }
91113
92- public closeOverlay ( event : CustomEvent < OverlayCloseDetail > ) : void {
114+ public closeOverlay ( content : HTMLElement ) : void {
93115 requestAnimationFrame ( ( ) => {
94- const overlayContent = event . detail . content ;
95- const overlay = this . overlays . find ( ( item ) =>
96- overlayContent . isSameNode ( item . overlayContent as HTMLElement )
97- ) ;
116+ const overlay = this . findOverlayForContent ( content ) ;
98117 this . hideAndCloseOverlay ( overlay ) ;
99118 } ) ;
100119 }
@@ -123,7 +142,7 @@ export class OverlayStack {
123142 } ;
124143
125144 private closeAllHoverOverlays ( ) : void {
126- for ( const overlay of this . overlays ) {
145+ for ( const overlay of this . overlays ( ) ) {
127146 if ( overlay . interaction === 'hover' ) {
128147 this . hideAndCloseOverlay ( overlay ) ;
129148 }
@@ -133,13 +152,8 @@ export class OverlayStack {
133152 private async hideAndCloseOverlay ( overlay ?: ActiveOverlay ) : Promise < void > {
134153 if ( overlay ) {
135154 await overlay . hide ( ) ;
136- const index = this . overlays . indexOf ( overlay ) ;
137- /* istanbul ignore else */
138- if ( index >= 0 ) {
139- this . overlays [ index ] . dispose ( ) ;
140- this . overlays . splice ( index , 1 ) ;
141- }
142- this . onChange ( this . overlays ) ;
155+ overlay . remove ( ) ;
156+ overlay . dispose ( ) ;
143157 }
144158 }
145159
@@ -164,9 +178,9 @@ export class OverlayStack {
164178
165179 this . handlingResize = true ;
166180 requestAnimationFrame ( ( ) => {
167- this . overlays . forEach ( ( overlay ) => {
181+ for ( const overlay of this . overlays ( ) ) {
168182 overlay . updateOverlayPosition ( ) ;
169- } ) ;
183+ }
170184 this . handlingResize = false ;
171185 } ) ;
172186 } ;
0 commit comments