github.com/grafana/pyroscope@v1.18.0/public/app/ui/LoadingOverlay.tsx (about) 1 import React, { ReactNode, useEffect, useState } from 'react'; 2 import LoadingSpinner from '@pyroscope/ui/LoadingSpinner'; 3 import cx from 'classnames'; 4 import styles from './LoadingOverlay.module.css'; 5 6 /** 7 * LoadingOverlay when 'active' will cover the entire parent's width/height with 8 * an overlay and a loading spinner 9 */ 10 export function LoadingOverlay({ 11 active = true, 12 spinnerPosition = 'center', 13 children, 14 delay = 250, 15 }: { 16 /** where to position the spinner. use baseline when the component's vertical center is outside the viewport */ 17 spinnerPosition?: 'center' | 'baseline'; 18 active: boolean; 19 children?: ReactNode; 20 /** delay in ms before showing the overlay. this evicts a flick */ 21 delay?: number; 22 }) { 23 const [isVisible, setVisible] = useState(false); 24 25 // Wait for `delay` ms before showing the overlay 26 // So that it feels snappy when server is fast 27 // https://www.nngroup.com/articles/progress-indicators/ 28 useEffect(() => { 29 if (active) { 30 const timeoutID = window.setTimeout(() => { 31 setVisible(true); 32 }, delay); 33 34 return () => clearTimeout(timeoutID); 35 } 36 37 setVisible(false); 38 return () => {}; 39 }, [active, delay]); 40 41 return ( 42 <div> 43 <div 44 className={cx( 45 styles.loadingOverlay, 46 !isVisible ? styles.unactive : null 47 )} 48 style={{ 49 alignItems: spinnerPosition, 50 }} 51 > 52 <LoadingSpinner size="46px" /> 53 </div> 54 {children} 55 </div> 56 ); 57 }