@@ -120,7 +120,6 @@ export const AppLayoutMixin = (superclass) =>
120120 constructor ( ) {
121121 super ( ) ;
122122 // TODO(jouni): might want to debounce
123- this . __boundResizeListener = this . _resize . bind ( this ) ;
124123 this . __drawerToggleClickListener = this . _drawerToggleClick . bind ( this ) ;
125124 this . __onDrawerKeyDown = this . __onDrawerKeyDown . bind ( this ) ;
126125 this . __closeOverlayDrawerListener = this . __closeOverlayDrawer . bind ( this ) ;
@@ -138,34 +137,13 @@ export const AppLayoutMixin = (superclass) =>
138137 connectedCallback ( ) {
139138 super . connectedCallback ( ) ;
140139
141- this . _blockAnimationUntilAfterNextRender ( ) ;
140+ this . __resizeObserver = new ResizeObserver ( ( entries ) => this . __onResize ( entries ) ) ;
141+ this . __resizeObserver . observe ( this ) ;
142+ this . __resizeObserver . observe ( this . $ . drawer ) ;
143+ this . __resizeObserver . observe ( this . $ . navbarTop ) ;
144+ this . __resizeObserver . observe ( this . $ . navbarBottom ) ;
142145
143- window . addEventListener ( 'resize' , this . __boundResizeListener ) ;
144146 this . addEventListener ( 'drawer-toggle-click' , this . __drawerToggleClickListener ) ;
145-
146- requestAnimationFrame ( ( ) => {
147- this . _updateOffsetSize ( ) ;
148- } ) ;
149-
150- this . _updateTouchOptimizedMode ( ) ;
151- this . _updateDrawerSize ( ) ;
152- this . _updateOverlayMode ( ) ;
153-
154- this . _navbarSizeObserver = new ResizeObserver ( ( ) => {
155- requestAnimationFrame ( ( ) => {
156- // Prevent updating offset size multiple times
157- // during the drawer open / close transition.
158- if ( this . __isDrawerAnimating ) {
159- this . __updateOffsetSizePending = true ;
160- } else {
161- this . _updateOffsetSize ( ) ;
162- }
163- } ) ;
164- } ) ;
165- this . _navbarSizeObserver . observe ( this . $ . navbarTop ) ;
166- this . _navbarSizeObserver . observe ( this . $ . navbarBottom ) ;
167- this . _navbarSizeObserver . observe ( this . $ . drawer ) ;
168-
169147 window . addEventListener ( 'close-overlay-drawer' , this . __closeOverlayDrawerListener ) ;
170148 window . addEventListener ( 'keydown' , this . __onDrawerKeyDown ) ;
171149 }
@@ -181,42 +159,70 @@ export const AppLayoutMixin = (superclass) =>
181159 } ) ;
182160
183161 this . $ . drawer . addEventListener ( 'transitionend' , ( ) => {
184- // Update offset size after drawer animation.
185- if ( this . __updateOffsetSizePending ) {
186- this . __updateOffsetSizePending = false ;
187- this . _updateOffsetSize ( ) ;
188- }
189-
190- // Delay resetting the flag until animation frame
191- // to avoid updating offset size again on resize.
192- requestAnimationFrame ( ( ) => {
193- this . __isDrawerAnimating = false ;
194- } ) ;
162+ this . __isDrawerAnimating = false ;
163+ this . __scheduleResize ( this . $ . drawer ) ;
195164 } ) ;
196165 }
197166
198167 /** @protected */
199168 disconnectedCallback ( ) {
200169 super . disconnectedCallback ( ) ;
201-
202- window . removeEventListener ( 'resize' , this . __boundResizeListener ) ;
170+ this . __resizeObserver . disconnect ( ) ;
203171 this . removeEventListener ( 'drawer-toggle-click' , this . __drawerToggleClickListener ) ;
204172 window . removeEventListener ( 'close-overlay-drawer' , this . __drawerToggleClickListener ) ;
205173 window . removeEventListener ( 'keydown' , this . __onDrawerKeyDown ) ;
206174 }
207175
208176 /** @private */
209177 __onNavbarSlotChange ( ) {
210- this . _updateTouchOptimizedMode ( ) ;
178+ this . __scheduleResize ( this . $ . navbarTop ) ;
179+ this . __scheduleResize ( this . $ . navbarBottom ) ;
211180 this . toggleAttribute ( 'has-navbar' , ! ! this . querySelector ( '[slot="navbar"]' ) ) ;
212181 }
213182
214183 /** @private */
215184 __onDrawerSlotChange ( ) {
216- this . _updateDrawerSize ( ) ;
185+ this . __scheduleResize ( this . $ . drawer ) ;
186+ this . __updateDrawerSize ( ) ;
217187 this . toggleAttribute ( 'has-drawer' , ! ! this . querySelector ( '[slot="drawer"]' ) ) ;
218188 }
219189
190+ /** @private */
191+ __onResize ( entries ) {
192+ cancelAnimationFrame ( this . __resizeRaf ) ;
193+
194+ const isHostResized = entries . some ( ( { target } ) => target === this ) ;
195+ const isNavbarResized = entries . some ( ( { target } ) => [ this . $ . navbarTop , this . $ . navbarBottom ] . includes ( target ) ) ;
196+
197+ const overlayMode = this . _getCustomPropertyValue ( '--vaadin-app-layout-drawer-overlay' ) === 'true' ;
198+ const touchOptimized = this . _getCustomPropertyValue ( '--vaadin-app-layout-touch-optimized' ) === 'true' ;
199+
200+ const drawerRect = this . $ . drawer . getBoundingClientRect ( ) ;
201+ const navbarTopRect = this . $ . navbarTop . getBoundingClientRect ( ) ;
202+ const navbarBottomRect = this . $ . navbarBottom . getBoundingClientRect ( ) ;
203+
204+ const isDrawerAnimating = this . __isDrawerAnimating ;
205+
206+ this . __resizeRaf = requestAnimationFrame ( ( ) => {
207+ if ( isHostResized ) {
208+ this . _blockAnimationUntilAfterNextRender ( ) ;
209+ this . __setOverlayMode ( overlayMode ) ;
210+ }
211+
212+ if ( isHostResized || isNavbarResized ) {
213+ this . __setTouchOptimized ( touchOptimized ) ;
214+ }
215+
216+ if ( ! isDrawerAnimating ) {
217+ this . __setOffsetSize ( {
218+ drawerRect,
219+ navbarTopRect,
220+ navbarBottomRect,
221+ } ) ;
222+ }
223+ } ) ;
224+ }
225+
220226 /**
221227 * A callback for the `primarySection` property observer.
222228 *
@@ -306,48 +312,27 @@ export const AppLayoutMixin = (superclass) =>
306312 }
307313 }
308314
309- /** @protected */
310- _updateDrawerSize ( ) {
315+ /** @private */
316+ __updateDrawerSize ( ) {
311317 const childCount = this . querySelectorAll ( '[slot=drawer]' ) . length ;
312- const drawer = this . $ . drawer ;
313-
314318 if ( childCount === 0 ) {
315- drawer . setAttribute ( 'hidden' , '' ) ;
319+ this . $ . drawer . setAttribute ( 'hidden' , '' ) ;
316320 this . style . setProperty ( '--_vaadin-app-layout-drawer-width' , 0 ) ;
317321 } else {
318- drawer . removeAttribute ( 'hidden' ) ;
322+ this . $ . drawer . removeAttribute ( 'hidden' ) ;
319323 this . style . removeProperty ( '--_vaadin-app-layout-drawer-width' ) ;
320324 }
321- this . _updateOffsetSize ( ) ;
322325 }
323326
324327 /** @private */
325- _resize ( ) {
326- this . _blockAnimationUntilAfterNextRender ( ) ;
327- this . _updateTouchOptimizedMode ( ) ;
328- this . _updateOverlayMode ( ) ;
329- }
330-
331- /** @protected */
332- _updateOffsetSize ( ) {
333- const navbar = this . $ . navbarTop ;
334- const navbarRect = navbar . getBoundingClientRect ( ) ;
335-
336- const navbarBottom = this . $ . navbarBottom ;
337- const navbarBottomRect = navbarBottom . getBoundingClientRect ( ) ;
338-
339- const drawer = this . $ . drawer ;
340- const drawerRect = drawer . getBoundingClientRect ( ) ;
341-
342- this . style . setProperty ( '--_vaadin-app-layout-navbar-offset-size' , `${ navbarRect . height } px` ) ;
343- this . style . setProperty ( '--_vaadin-app-layout-navbar-offset-size-bottom' , `${ navbarBottomRect . height } px` ) ;
328+ __setOffsetSize ( { drawerRect, navbarTopRect, navbarBottomRect } ) {
344329 this . style . setProperty ( '--_vaadin-app-layout-drawer-offset-size' , `${ drawerRect . width } px` ) ;
330+ this . style . setProperty ( '--_vaadin-app-layout-navbar-offset-size' , `${ navbarTopRect . height } px` ) ;
331+ this . style . setProperty ( '--_vaadin-app-layout-navbar-offset-size-bottom' , `${ navbarBottomRect . height } px` ) ;
345332 }
346333
347- /** @protected */
348- _updateOverlayMode ( ) {
349- const overlay = this . _getCustomPropertyValue ( '--vaadin-app-layout-drawer-overlay' ) === 'true' ;
350-
334+ /** @private */
335+ __setOverlayMode ( overlay ) {
351336 if ( ! this . overlay && overlay ) {
352337 // Changed from not overlay to overlay
353338 this . _drawerStateSaved = this . drawerOpened ;
@@ -487,12 +472,9 @@ export const AppLayoutMixin = (superclass) =>
487472 return ( customPropertyValue || '' ) . trim ( ) . toLowerCase ( ) ;
488473 }
489474
490- /** @protected */
491- _updateTouchOptimizedMode ( ) {
492- const touchOptimized = this . _getCustomPropertyValue ( '--vaadin-app-layout-touch-optimized' ) === 'true' ;
493-
475+ /** @private */
476+ __setTouchOptimized ( touchOptimized ) {
494477 const navbarItems = this . querySelectorAll ( '[slot*="navbar"]' ) ;
495-
496478 if ( navbarItems . length > 0 ) {
497479 Array . from ( navbarItems ) . forEach ( ( navbar ) => {
498480 if ( navbar . getAttribute ( 'slot' ) . indexOf ( 'touch-optimized' ) > - 1 ) {
@@ -518,8 +500,6 @@ export const AppLayoutMixin = (superclass) =>
518500 } else {
519501 this . $ . navbarBottom . removeAttribute ( 'hidden' ) ;
520502 }
521-
522- this . _updateOffsetSize ( ) ;
523503 }
524504
525505 /** @protected */
@@ -533,6 +513,18 @@ export const AppLayoutMixin = (superclass) =>
533513 } ) ;
534514 }
535515
516+ /**
517+ * Forces the ResizeObserver to re-report the size of the given element,
518+ * scheduling a new {@link __onResize} callback even if the size hasn't changed.
519+ *
520+ * @param {Element } element
521+ * @private
522+ */
523+ __scheduleResize ( element ) {
524+ this . __resizeObserver . unobserve ( element ) ;
525+ this . __resizeObserver . observe ( element ) ;
526+ }
527+
536528 /**
537529 * App Layout listens to `close-overlay-drawer` on the window level.
538530 * A custom event can be dispatched and the App Layout will close the drawer in overlay.
0 commit comments