import { useRouter } from 'next/router'; import { useEffect } from 'react'; import { useProgressBar } from './useProgressBar'; // https://github.com/twbs/bootstrap/blob/v5.3.0-alpha1/scss/_variables.scss#L1529 const transitionSpeed = 600; // https://gist.github.com/tkrotoff/db8a8106cc93ae797ea968d78ea28047 // https://stackoverflow.com/q/60755316 // https://stackoverflow.com/q/55624695 export function RouterProgressBar(props?: Parameters<typeof useProgressBar>[0]) { const { events } = useRouter(); const { width, start, complete, reset } = useProgressBar({ transitionSpeed, ...props }); useEffect(() => { events.on('routeChangeStart', start); events.on('routeChangeComplete', complete); events.on('routeChangeError', reset); // Typical case: "Route Cancelled" return () => { events.off('routeChangeStart', start); events.off('routeChangeComplete', complete); events.off('routeChangeError', reset); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return width > 0 ? ( <div className="progress fixed-top bg-transparent rounded-0" style={{ height: 3, // GitHub turbo-progress-bar height is 3px zIndex: 1091 // $zindex-toast + 1 => always visible }} > <div className="progress-bar" style={{ width: `${width}%`, //transition: 'none', // https://github.com/twbs/bootstrap/blob/v5.3.0-alpha1/scss/_variables.scss#L1529 transition: `width ${ // Why transition is 0 if width < 1% ? // If a `complete()` (width 100%) has been aborted (by a `start()`), // the slow CSS transition will prevent the progress bar from visually reaching width 1% // Without this hack (i.e. forcing the stop of the previous CSS transition), // the progress bar would temporary look like K 2000 (Knight Rider) car front-mounted scanner width > 1 ? transitionSpeed : 0 }ms ease` }} /> </div> ) : null; }