@@ -2,12 +2,13 @@ import '../colors/colors.js';
22import '../loading-spinner/loading-spinner.js' ;
33import { css , html , LitElement , nothing } from 'lit' ;
44import { getOffsetParent } from '../../helpers/dom.js' ;
5+ import { styleMap } from 'lit/directives/style-map.js' ;
56
67const BACKDROP_DELAY_MS = 800 ;
78const FADE_DURATION_MS = 500 ;
89const SPINNER_DELAY_MS = FADE_DURATION_MS ;
910
10- const LOADING_SPINNER_BUFFER = 300 ;
11+ const LOADING_SPINNER_MINIMUM_BUFFER = 100 ;
1112
1213const reduceMotion = matchMedia ( '(prefers-reduced-motion: reduce)' ) . matches ;
1314
@@ -24,6 +25,7 @@ class LoadingBackdrop extends LitElement {
2425 */
2526 shown : { type : Boolean } ,
2627 _state : { type : String , reflect : true } ,
28+ _spinnerTop : { type : Number , reflect : true }
2729 } ;
2830 }
2931
@@ -60,8 +62,7 @@ class LoadingBackdrop extends LitElement {
6062 d2l-loading-spinner {
6163 opacity: 0;
6264 position: absolute;
63- top: ${ LOADING_SPINNER_BUFFER } px;
64- transition: opacity ${ FADE_DURATION_MS } ms ease-in ${ SPINNER_DELAY_MS } ms, top .2s ease-in;
65+ transition: opacity ${ FADE_DURATION_MS } ms ease-in ${ SPINNER_DELAY_MS } ms;
6566 transition
6667 }
6768 :host([_state="shown"]) d2l-loading-spinner.fixed {
@@ -87,18 +88,14 @@ class LoadingBackdrop extends LitElement {
8788 super ( ) ;
8889 this . shown = false ;
8990 this . _state = 'hidden' ;
90-
91- }
92-
93- firstUpdated ( ) {
94- document . addEventListener ( 'scroll' , this . #updateLoadingSpinnerPos. bind ( this ) ) ;
91+ this . _spinnerTop = LOADING_SPINNER_MINIMUM_BUFFER ;
9592 }
9693
9794 render ( ) {
9895 if ( this . _state === 'hidden' ) return nothing ;
9996 return html `
10097 < div class ="backdrop " @transitionend ="${ this . #handleTransitionEnd} " @transitioncancel ="${ this . #hide} "> </ div >
101- < d2l-loading-spinner > </ d2l-loading-spinner >
98+ < d2l-loading-spinner style = ${ styleMap ( { top : ` ${ this . _spinnerTop } px` } ) } > </ d2l-loading-spinner >
10299 ` ;
103100 }
104101 updated ( changedProperties ) {
@@ -108,9 +105,10 @@ class LoadingBackdrop extends LitElement {
108105 }
109106 }
110107
111- if ( this . _state !== 'hidden' ) {
112- this . #updateLoadingSpinnerPos( ) ;
113- } ;
108+ if ( this . #mustRepositionSpinner) {
109+ this . #centerLoadingSpinner( ) ;
110+ this . #mustRepositionSpinner = false ;
111+ }
114112 }
115113 willUpdate ( changedProperties ) {
116114 if ( changedProperties . has ( 'shown' ) ) {
@@ -121,6 +119,29 @@ class LoadingBackdrop extends LitElement {
121119 }
122120 }
123121 }
122+ #mustRepositionSpinner;
123+
124+ #centerLoadingSpinner( ) {
125+ if ( this . _state === 'hidden' ) { return ; }
126+
127+ const loadingSpinner = this . shadowRoot . querySelector ( 'd2l-loading-spinner' ) ;
128+ if ( ! loadingSpinner ) { return ; }
129+
130+ const boundingRect = this . getBoundingClientRect ( ) ;
131+
132+ // Calculate the centerpoint of the visible portion of the element
133+ const upperVisibleBound = Math . max ( 0 , boundingRect . top ) ;
134+ const lowerVisibleBound = Math . min ( window . innerHeight , boundingRect . bottom ) ;
135+ const visibleHeight = lowerVisibleBound - upperVisibleBound ;
136+ const centeringOffset = visibleHeight / 2 ;
137+
138+ // Calculate if an offset is required to move to the top of the viewport before centering
139+ const topOffset = Math . max ( 0 , - boundingRect . top ) ; // measures the distance below the top of the viewport, which is negative if the element starts above the viewport
140+ const newPosition = centeringOffset + topOffset ;
141+
142+ this . _spinnerTop = Math . max ( LOADING_SPINNER_MINIMUM_BUFFER , newPosition ) ;
143+ }
144+
124145 #fade( ) {
125146 if ( reduceMotion ) {
126147 this . #hide( ) ;
@@ -141,6 +162,8 @@ class LoadingBackdrop extends LitElement {
141162 if ( containingBlock . dataset . initiallyInert !== '1' ) containingBlock . removeAttribute ( 'inert' ) ;
142163 }
143164 #show( ) {
165+ this . #mustRepositionSpinner = true ;
166+
144167 this . _state = reduceMotion ? 'shown' : 'showing' ;
145168
146169 const containingBlock = getOffsetParent ( this ) ;
@@ -149,25 +172,6 @@ class LoadingBackdrop extends LitElement {
149172
150173 containingBlock . setAttribute ( 'inert' , 'inert' ) ;
151174 }
152- #updateLoadingSpinnerPos( ) {
153- if ( this . _state === 'hidden' ) { return ; }
154-
155- const loadingSpinner = this . shadowRoot . querySelector ( 'd2l-loading-spinner' ) ;
156- const boundingRect = this . getBoundingClientRect ( ) ;
157- const top = boundingRect . top ;
158-
159- if ( top > 0 ) {
160- const innerHeight = window . innerHeight ;
161- const visibleHeight = innerHeight - boundingRect . top ;
162- const centerPoint = visibleHeight / 2 ;
163- const minimumOffset = 100 ;
164- const adjustedOffset = Math . max ( minimumOffset , centerPoint ) ;
165- loadingSpinner . style . top = `${ adjustedOffset } px` ;
166- loadingSpinner . classList . remove ( 'fixed' ) ;
167- } else {
168- loadingSpinner . classList . add ( 'fixed' ) ;
169- }
170- }
171175
172176}
173177
0 commit comments